requests 超时、重试、SSL 报错?9 个高频问题与一整张排错对照表

requests 超时、重试、SSL 报错?9 个高频问题与一整张排错对照表

先给结论:requests 的默认配置几乎全是"危险默认"------默认没有超时、默认不重试、默认每次新建连接。绝大多数线上事故不是 requests 的 bug,而是这三个默认没被覆盖。

下面 9 个坑,按线上出现频率排序,每个都给现象、根因、修法。

坑 1:不设 timeout,请求永远挂着

现象:程序卡死几小时,日志没有任何报错,线程/协程全部耗尽。

根因 :requests 的 timeout 默认值是 None,即无限等待。服务端不返回,客户端就一直等着。

python 复制代码
# 危险:没有超时
r = requests.get(url)

# 正确:分别设置连接超时和读取超时
r = requests.get(url, timeout=(3.05, 10))

timeout=(3.05, 10) 表示连接超时 3.05 秒、读取超时 10 秒。这两个数是不同的东西 :连接超时是 TCP 握手,读取超时是"连上之后等多久收到下一个字节"。只传一个数字(timeout=5)则表示两者都用 5 秒。

坑 2:以为 requests 会自动重试(它不会)

现象:偶发的 502/连接重置直接抛异常,明明重试一次就好。

根因 :requests 本身不做任何重试 。重试要挂 urllib3 的 Retry 到 HTTPAdapter 上。

python 复制代码
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

retry = Retry(
    total=3,                      # 总重试次数
    backoff_factor=0.5,           # 退避:0.5s, 1s, 2s
    status_forcelist=[429, 500, 502, 503, 504],
    allowed_methods=["GET", "HEAD"],   # 只对幂等方法重试
)
s = requests.Session()
s.mount("https://", HTTPAdapter(max_retries=retry))

注意 allowed_methods:默认只重试幂等方法。如果你的重试列表里放了 POST,重复下单这类非幂等请求会出大事故。

坑 3:verify=False 一关了之

现象 :SSLError: certificate verify failed,加 verify=False 后 warning 刷屏。

根因 :证书链校验失败(内网自签证书、系统 CA 过旧、代理中间人证书)。verify=False 只是关掉校验,等于放弃了中间人攻击防护 ,urllib3 会持续打 InsecureRequestWarning。

修法(按优先级):

  1. 用 certifi 的最新 CA:requests.get(url, verify=certifi.where())
  2. 内网自签证书:把 CA 证书路径传给 verify="/path/to/ca.pem"
  3. 仅在本机调试时临时 verify=False,并配 urllib3.disable_warnings()

坑 4:每次都 requests.get,连接池白建

现象:QPS 上不去,TIME_WAIT 堆积。

根因 :requests.get() 每次都新建一个 Session,握手、DNS、TLS 全部重来。

python 复制代码
# 慢:每次新建连接
for u in urls:
    requests.get(u)

# 快:复用 Session(自动连接池 + keep-alive)
with requests.Session() as s:
    for u in urls:
        s.get(u, timeout=(3, 10))

坑 5:Session 跨线程共享

现象:多线程下偶发莫名其妙的连接错误、响应串号。

根因 :Session 不是线程安全的。它内部的连接池虽然有一定并发能力,但 cookies、适配器状态并非为并发设计。

修法 :每个线程一个 Session,或用 threading.local() 存,或改用 httpx(明确区分 Client 的线程/异步模型)。

坑 6:中文乱码

现象 :response.text 出现 æ\u0088\ue105 之类乱码。

根因 :服务器返回的 Content-Type 没带 charset 时,requests 按 HTTP 默认 ISO-8859-1 猜,text 就按错编码解。

python 复制代码
r = requests.get(url)
# 先看它猜成了什么
print(r.encoding, r.apparent_encoding)  # ISO-8859-1  vs  utf-8
r.encoding = r.apparent_encoding        # 或 r.encoding = "utf-8"
print(r.text)

判据 :r.encoding 取自响应头,r.apparent_encoding 是 chardet/charset_normalizer 实际探测的结果。两者不一致时,以探测结果为准。

坑 7:data= 和 json= 分不清

现象:后端收不到参数,或收到的是一坨字符串。

写法 Content-Type 请求体
data={"a":1} application/x-www-form-urlencoded a=1
json={"a":1} application/json {"a": 1}
data=json.dumps(d) 仍是 form 表单(除非手动加头) 字符串被当表单值

想要 JSON 就直接用 json= 参数;手工 data=json.dumps(...) 必须自己补 headers={"Content-Type": "application/json"}。

坑 8:下载大文件把内存打爆

现象:下载几百 MB 文件,内存飙到几 GB。

根因 :response.content 会一次性把整个响应体读进内存。

python 复制代码
with requests.get(url, stream=True, timeout=(3, 30)) as r:
    r.raise_for_status()
    with open("big.zip", "wb") as f:
        for chunk in r.iter_content(chunk_size=8192):
            if chunk:
                f.write(chunk)

stream=True 之后必须消费或关闭响应,否则连接不会归还连接池(见坑 9)。

坑 9:响应没关,连接池耗尽

现象 :跑一段时间报 ConnectionError: Max retries exceeded,或 urllib3 提示连接池已满。

根因 :拿到响应后只取了 status_code 没读 body,或用 stream=True 后没读完也没 close(),连接就一直占着。

python 复制代码
r = requests.get(url, stream=True)
r.close()                       # 显式归还
# 更好的写法
with requests.get(url, stream=True) as r:
    ...

一整张排错对照表

现象 根因 修法
程序永久挂起 timeout 默认 None 始终传 timeout=(3, 10)
偶发 502 没人重试 requests 不自动重试 Retry + HTTPAdapter
SSLError / warning 刷屏 证书链校验失败 verify=certifi.where() 或指定 CA
QPS 上不去 每次新建连接 复用 Session
多线程偶发串号 Session 非线程安全 每线程一个 Session
中文乱码 默认 ISO-8859-1 设 r.encoding = r.apparent_encoding
后端收不到 JSON data= 发成表单 用 json=
下载大文件 OOM content 全读进内存 stream=True + iter_content
连接池耗尽 响应未关闭 with 或显式 close()

最后

requests 的三个危险默认:无超时、不重试、不复用连接。 把它们覆盖掉,能消掉线上八成以上的 HTTP 相关故障。再配一条:所有响应都用 with 包住,别让连接泄漏。

你在 requests 上踩过最坑的一次是什么?评论区说说。

相关推荐
悟道书生20 小时前
若依 RBAC 权限控制学习笔记
java·网络·笔记·sql·学习·vue
电梯界知识分子20 小时前
景德镇老房重新设计阶段规划楼梯与电梯,1.7m×1.6m空间装400kg观光电梯,棕色框架茶色玻璃适配中式装修
大数据·服务器·前端·网络·家用电梯
Yiran_G21 小时前
双频 Wi-Fi 6 + 蓝牙 5.4:无声讯通 WS8712 模组的开发与集成要点
网络·嵌入式硬件·物联网·智能家居
dsadas21 小时前
ospf宣告网段的理解
网络协议
凯基迪科技21 小时前
STM32G系列(G0/G4)芯片解密程序提取RDP读保护解析
网络·stm32·安全
靠谱的工程师朋友21 小时前
电子会计档案管理软件科普 核心能力与选型要点解析
网络·数据库·人工智能·电子会计档案
萌动的小火苗21 小时前
MQTT的QoS0、QoS1、QoS2有什么区别?
开发语言·网络·python·php·信息与通信
A黄俊辉A21 小时前
虚拟机中的 桥接,NAT,仅主机模式的区别
网络·智能路由器
牢姐与蒯21 小时前
Linux网络篇——TCP(一)之手搓TCP,并实现词典和远程命令
linux·网络·tcp/ip
科技小登1 天前
CC攻击防护哪家好?Web安全加速、WAF与Bot管理同入口方案对比
网络·安全·web安全