chunkedencodingerror通常不是requests的bug,而是服务端提前关闭连接,常见于nginx超时、反向代理限制或后端框架未正确处理流式请求;需通过curl复现、抓包分析及服务端配置(如proxy_read_timeout、flask/django流式接收)协同排查修复。

ChunkedEncodingError 通常不是 Requests 的 bug,而是服务端提前关闭连接
当你用 requests.post() 上传大文件(比如几百 MB 以上)时遇到 ChunkedEncodingError: ('Connection broken: IncompleteRead(0 bytes read)', IncompleteRead(0 bytes read)),大概率不是你代码写错了,而是服务端在接收过程中主动断开了连接——常见于 Nginx 超时、反向代理限制、或后端框架(如 Flask/Django)未正确处理流式请求。
验证这点最直接的方式:用 curl -X POST -F "file=@large.zip" http://your-api/ 复现相同错误。如果 curl 也失败,基本可锁定服务端问题。
- Nginx 默认
client_max_body_size是 1MB,超限会直接返回 413,但若设得过大而proxy_read_timeout或proxy_send_timeout过短(如默认 60s),就容易触发连接中断 - Flask 默认不启用流式接收,
request.files['file'].read()会把整个文件读进内存,超时或 OOM 都会导致连接断开 - Django 的
FILE_UPLOAD_MAX_MEMORY_SIZE和DATA_UPLOAD_MAX_MEMORY_SIZE也会在阈值触发时静默截断
用 requests 的 streaming + timeout 控制避免客户端“误判”断连
Requests 默认会把整个文件读入内存再发出去(除非你手动控制),这对大文件既慢又危险。配合合理的超时和分块读取,能让客户端更稳健地应对网络抖动或服务端延迟。
关键不是关掉 chunked encoding,而是让上传过程可控:
- 永远显式设置
timeout:至少包含(connect_timeout, read_timeout)元组,例如timeout=(5, 300)(连接 5 秒,读响应最长 5 分钟) - 用
open(..., "rb")+files={"file": (filename, fp, mime_type)}让 requests 自动流式发送,不要先read()整个文件 - 避免使用
data=...传二进制内容,它会禁用 chunked encoding 并强制内存加载 - 如需自定义分块(例如做进度条),可用
iter(lambda: fp.read(8192), b"")手动迭代,但必须配stream=True和手动构造Content-Length
示例安全写法:
with open("huge.bin", "rb") as f:
resp = requests.post(
"https://api.example.com/upload",
files={"file": ("huge.bin", f, "application/octet-stream")},
timeout=(5, 600) # 给足服务端处理时间
)
服务端必须支持流式接收,否则客户端再稳也没用
客户端发的是 chunked,不代表服务端能接得住。很多 Web 框架默认把整个请求体缓存到内存或临时文件,没等读完就超时或崩溃,导致 TCP 连接被重置——这时 Requests 就报 ChunkedEncodingError。
- Flask:必须用
stream=True初始化 request,并手动迭代request.stream.read(8192);不能碰request.files或request.get_data() - Django:用
request.FILES["file"].chunks(chunk_size=8192),别调.read() - FastAPI:参数声明为
UploadFile即可,默认流式;但注意file.read()仍会全量加载,应改用await file.read(8192)异步分块 - Nginx:确认
client_max_body_size、proxy_buffering off、proxy_request_buffering off(后者对大文件上传很关键)
调试时优先抓包看哪一端先断开 TCP 连接
单纯看 Python 报错容易误导。真正要定位的,是三次握手后谁先发 FIN 或 RST。
- 用
tcpdump -i any port 80 or port 443 -w upload.pcap抓包,Wireshark 打开后过滤tcp.analysis.retransmission || tcp.analysis.ack_lost - 如果服务端 IP 在上传中途发了 RST,说明它主动终止——查服务端日志、超时配置、OOM killer 记录
- 如果客户端发了 FIN 后没收到 ACK,可能是本地防火墙、代理或 NAT 设备干扰
- Requests 的
StreamConsumedError或ProtocolError有时是底层 urllib3 重试失败的残留,关掉重试(requests.adapters.HTTPAdapter(max_retries=0))有助于看清原始错误
大文件上传本质是协同问题:客户端得流着发,服务端得流着收,中间链路得允许长连接。任一环节卡住,都会表现为 ChunkedEncodingError —— 它只是表象,不是病因。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











