requests 默认不重试、无超时、4xx不抛异常是接口调用失败主因;必须显式设 timeout=(connect, read),检查 status_code 或用 raise_for_status(),GET 可安全重试而 POST 需幂等,Session 复用连接并管理 Cookie/Auth。
requests 默认不自动重试,超时默认是永久等待,4xx 错误不会抛异常——这三点是绝大多数接口调用失败却查不出原因的根源。
不设 timeout 会导致请求卡死在 DNS 解析、连接建立或响应读取任一环节,尤其在容器或云函数中会直接触发超时熔断。
timeout 是个二元组:(connect_timeout, read_timeout),例如 timeout=(3, 10) 表示连接最多等 3 秒,连上后读响应最多等 10 秒timeout=5)等价于 timeout=(5, 5),但生产环境建议拆开控制read_timeout,但 connect_timeout 建议保持 ≤3 秒response.status_code
requests 把 HTTP 状态码 ≥400 视为“合法响应”,response.raise_for_status() 才会触发 HTTPError。很多同学写了 r = requests.post(...) 却没检查状态码,结果拿到 401 Unauthorized 还以为数据正常。
r.status_code == 200 或使用 r.raise_for_status()
raise_for_status() 对 4xx/5xx 统一抛 requests.exceptions.HTTPError,可统一捕获{"code": 500, "msg": "库存不足"},这类需额外解析 r.json().get("code")
requests 本身不带重试逻辑,靠 urllib3.Ret 配合
ryrequests.adapters.HTTPAdapter 实现。盲目全局启用重试可能放大雪崩风险(比如对 POST 接口重试三次,导致重复下单)。
status_forcelist=(500, 502, 503, 504) 明确限定重试范围import requests from urllib3.util.retry import Retry from requests.adapters import HTTPAdaptersession = requests.Session() retry_strategy = Retry( total=2, backoff_factor=1, status_forcelist=(500, 502, 503, 504), allowed_methods=["HEAD", "GET", "OPTIONS"] ) adapter = HTTPAdapter(max_retries=retry_strategy) session.mount("http://", adapter) session.mount("https://", adapter)
后续所有 session.get() / session.post() 都自动带重试
r = session.get("https://www./link/46b315dd44d174daf5617e22b3ac94ca", timeout=(3, 10))
每次新建 requests.get() 都会创建新连接、丢弃 Cookie 和认证上下文;高频调用时既低效又容易被限流。用 requests.Session() 可复用 TCP 连接、自动维护 Set-Cookie、并支持预置 auth 或 headers。
post("/login") 后,后续请求自动携带服务端下发的 sessionid Cookie"Authorization: Bearer xxx",改用 session.auth = ("user", "pass") 或 session.headers.update({...})
真正难的不是发请求,而是判断该不该重试、在哪一层校验状态、以及如何让失败表现得可追溯——这些细节往往藏在 response.headers、response.elapsed 和日志上下文里,而不是文档首页的那行 requests.get(url)。