DEBUG.WIKI
PanstarCloud:部署应用,接入 AI,云服务器与 AI 网关
雨云;给项目一台云服务器
IPPeak:从目标地区访问网页,住宅代理、SEO 监测、广告验证

urllib3 上传返回成功却是空文件,检查 blocksize 是否为 0

文件型正文使用 blocksize=0 时,零长度读取可能被当成 EOF,HTTP 200 仍不保证上传完整。去掉零值配置,采用正整数分块,并核对接收端长度和业务状态。

文件里有内容,urllib3 上传返回 HTTP 200,接收端却得到空正文。若调用方设置过 blocksize=0,先检查这个值,不要把它理解成“自动选择大小”或“读完整个文件”。

在文件型请求体路径里,urllib3 用 body.read(blocksize) 分块读取。零长度读取返回空字节串,发送循环就认为文件已经结束;采用 chunked framing 时,仍可以发出合法的结束块,因此服务端未必返回协议错误。

同一文件,bytes 正文和文件对象可能不同

bytes 正文与具有 read() 的文件对象走不同分支。把小文件一次性读成 bytes 后能上传,只能帮助缩小范围,不能证明原文件流路径也正常,更不能据此要求所有大文件一次性装入内存。

这条故障在 2.7.1 的开发构建中有完整记录。正式 2.8.0 的文件分块读取仍按传入的 blocksize 调用 read(),相关连接构造也未在这里拒绝零值;不能把开发版号当正式发行,更不能只凭升级到 2.8.0 就排除这条配置路径。

先保留客户端版本、传入的 blocksize、请求体类型,以及接收端确认的长度。日志只记录长度或受控摘要,避免把文件内容和认证信息一起输出。

去掉零值配置,或明确使用正整数

如果没有专门的分块需求,移除自行添加的 blocksize=0,使用连接的默认分块大小。确实要配置时,使用符合项目内存与传输要求的正整数,并在配置入口校验。下面仅建立客户端,不会自行发送请求:

import urllib3

blocksize = 16 * 1024
if blocksize <= 0:
    raise ValueError("upload blocksize must be positive")
http = urllib3.PoolManager(blocksize=blocksize)

示例只展示这一项参数。已有代理、证书、超时、连接池和重试策略应继续保留,不要用一个新的无配置客户端悄悄替换它们。

也不要把 -1 当作通用修复。对于普通文件,read(-1) 可能一次读入全部剩余内容,改变大文件的内存需求;其他文件型对象的行为还要按其接口确定。问题需要的是明确、有界的读取大小。

重新提交前,先确认上一次发生了什么

HTTP 200 只说明服务端接受并响应了那次请求,不保证收到了期望字节。上传接口可能已经创建空对象、占用了业务编号,或执行了其他操作。先查询已提交对象的长度、摘要与业务状态,再按接口的幂等和覆盖约定决定是否重传,不能把所有成功响应都当作“什么也没发生”。

在受控接收端分别覆盖非空文件、空文件和多个块的大文件,核对字节总数与完整内容;文件句柄必须覆盖整个发送范围,起始位置也应与预期一致。如果移除零值后仍为空,再检查文件是否已在 EOF、是否被提前关闭,以及是否经过重定向。那些路径需要单独处理,不应继续盲调 blocksize。