Python Requests POST超时致连接提前关闭问题求助
核心原因:你误解了requests timeout参数的实际行为
requests的timeout参数默认会同时设置连接超时(connect timeout)和读取超时(read timeout),但这里的读取超时并非「总请求时长限制」——它是从TCP连接建立后开始计时,等待服务器返回任何响应数据的最大时间,包括等待服务器返回100 Continue(允许继续发送请求体的信号)的时间,以及上传完成后等待服务器返回最终响应的时间。
当你上传大文件且未开启流式上传时,requests会先把整个文件加载到内存,再一次性发送到Nginx。如果加载+发送的总时长超过了timeout设置的10秒,而此时Nginx还在缓冲请求体(未返回任何响应),requests就会触发读取超时,主动关闭连接。这就导致Nginx收到客户端断开的信号,抛出client prematurely closed connection错误,同时因为请求体未接收完整,只能向后端转发空请求体。
至于你提到requests未抛出异常,大概率是异常捕获逻辑有遗漏——正常情况下触发timeout时,requests会抛出requests.exceptions.Timeout异常,建议检查代码中的try-except块是否覆盖了该异常。
发送与读取字节的timeout机制差异
- 发送字节(上传阶段):requests本身没有专门限制「发送请求体总时长」的timeout参数,上传过程的耗时不会直接触发timeout,除非在上传前等待服务器
100 Continue信号的时间超过了读取超时。 - 读取字节(接收响应阶段):读取timeout严格限制从连接建立后,到服务器返回第一个响应字节的最大间隔时间,以及后续响应字节之间的空闲间隔时间。如果服务器在规定时间内没有返回任何数据,requests就会主动断开连接。
解决方案:正确设置timeout并优化上传方式
1. 拆分timeout为连接超时和读取超时
不要直接传单个数值,而是用元组明确区分,给读取超时设置足够大的数值(适配大文件上传的耗时):
# 连接超时5秒,读取超时300秒(5分钟),可根据实际上传时长调整 requests.post(upload_url, files=your_files, timeout=(5, 300))
2. 开启流式上传避免内存过载
使用stream=True,并直接传入文件对象,让requests分块发送文件,既不会一次性把大文件加载到内存,也能避免因加载文件耗时过长触发超时:
with open('large_file.bin', 'rb') as f: requests.post(upload_url, data=f, timeout=(5, 300), stream=True)
3. 调整Nginx配置适配大文件上传
确保Nginx的请求体缓冲配置合理,避免因为Nginx端的限制导致上传中断:
client_max_body_size:设置为足够容纳大文件的大小,比如100m;client_body_buffer_size:适当调大,减少Nginx写磁盘的频率,提升上传速度,比如16m。
内容的提问来源于stack exchange,提问作者ElJeffe

