requests.get() 默认不抛出4xx/5xx异常,需显式调用raise_for_status()触发HTTPError;该异常含状态码与reason,可据此区分4xx(客户端错误,不重试)和5xx(服务端错误,可指数退避重试)。

requests.get() 返回 4xx/5xx 时默认不抛异常
requests 库默认把 404、500 这类响应当作“成功请求”处理,response.status_code 是对应值,但 response.raise_for_status() 不会自动调用。这意味着你得手动判断,否则容易漏掉服务端报错。
常见错误现象:代码跑通没报错,但 response.json() 报 JSONDecodeError,因为返回的是 HTML 错误页(比如 Nginx 404 页面)或空响应体;或者后续逻辑拿不到预期字段,静默失败。
- 必须显式调用
response.raise_for_status()才能触发requests.exceptions.HTTPError - 该方法只对 4xx/5xx 状态码抛异常,2xx/3xx 均不处理
- 异常信息里包含状态码和 reason(如
404 Client Error: Not Found for url: ...),可直接用于日志或用户提示
捕获 HTTPError 并区分 4xx 和 5xx 场景
4xx 通常代表客户端问题(如参数错、权限不足、资源不存在),5xx 是服务端问题(如超时、数据库挂了)。两者重试策略不同:4xx 一般不该重试,5xx 可考虑指数退避重试。
示例中用 e.response.status_code 提取状态码,比解析字符串更可靠:
立即学习“Python免费学习笔记(深入)”;
try:
resp = requests.get("https://api.example.com/data")
resp.raise_for_status()
return resp.json()
except requests.exceptions.HTTPError as e:
if 400 <= e.response.status_code < 500:
# 客户端错误:检查 URL、headers、payload
raise ValueError(f"Client error: {e.response.status_code}")
elif 500 <= e.response.status_code < 600:
# 服务端错误:可记录并稍后重试
raise ConnectionError(f"Server error: {e.response.status_code}")
else:
raise
避免在 .json() 上二次崩溃
response.json() 在响应体为空、Content-Type 不是 application/json、或内容不是合法 JSON 时会抛 JSONDecodeError,这跟 HTTP 状态码无关——哪怕返回 200 OK 也可能崩。
- 先确认
response.status_code == 200再调.json(),否则可能混淆错误源头 - 更稳妥做法:用
response.text查看原始响应体,尤其当遇到404却拿到 HTML 时 - 若 API 文档明确返回 JSON,可在
raise_for_status()后加response.headers.get("content-type", "").startswith("application/json")做二次校验
requests.Session() 中统一处理错误响应
如果项目里大量接口调用,重复写 raise_for_status() 和异常分支容易遗漏。可以用 Session.hooks["response"] 注入预处理逻辑,但要注意:钩子函数不能改变 response 对象本身,只能做检查或记录。
- 推荐方式:封装一个
safe_request()函数,内部统一调用raise_for_status()并按需解析 JSON - 避免在 hooks 里直接 raise 异常,会导致 requests 内部流程中断,部分字段(如
response.history)可能不可用 - 若需日志,钩子里记
response.status_code和response.url就够,详细错误仍应在业务层捕获处理
真正麻烦的不是状态码转异常,而是 4xx/5xx 后怎么决定下一步——是提示用户改参数,还是自动降级,或是切备用接口。这些逻辑得贴着业务走,库只负责把裸状态码变成可捕获的信号。


















