通过代理IP上传文件时,客户端可能遇到 400、417 Expectation Failed、请求体被截断或服务端显示“没有文件”。这类问题往往不是出口IP,而是 multipart 请求的边界、长度、Expect: 100-continue 预期握手,或代理/网关对请求体的缓冲方式不一致。排查时应优先保存请求元数据和服务端接收结果,不要把真实文件或凭据发到第三方测试站。
multipart/form-data的boundary必须前后一致
上传请求的 Content-Type 会包含一个 boundary,例如 multipart/form-data; boundary=...;请求体中的每个分隔线都必须使用同一值,并以结束边界收尾。手工拼接请求头而让客户端库自动生成请求体,或反过来重复设置 Content-Type,都可能导致边界不匹配。
curl -v --proxy http://user:password@proxy.example:port -F 'file=@/path/to/test.bin' -F 'purpose=health-check' https://upload.example.test/api
示例中的文件、凭据和地址是占位符。使用成熟客户端生成 multipart,记录请求头名称和响应状态即可,不要在日志中保存文件内容或完整Authorization。
Expect: 100-continue会多一个握手阶段
当请求体较大或客户端启用 Expect: 100-continue 时,客户端可能先发送请求头,等待服务端确认后才上传正文。某些代理、旧网关或应用框架对该机制处理不完整,会出现等待、417或请求体根本未发送。可在自有接口上做对照:
curl -v -H 'Expect:' --proxy http://user:password@proxy.example:port -F 'file=@/path/to/test.bin' https://upload.example.test/api
如果去掉Expect后成功,说明问题集中在预期握手或中间层兼容性;不要据此推断所有目标站都应关闭该头,是否启用应由服务端能力和安全策略决定。
Content-Length、分块与代理缓冲
客户端可能使用固定 Content-Length,也可能使用分块传输。代理或网关如果重新缓冲请求体,需要正确更新长度和传输方式;如果中途超时或限制请求体大小,服务端可能只收到部分边界。对自有网关,比较入口收到的长度、上游转发长度、已解析文件大小和请求ID。
按三组变量做最小对照
- 同一小文件、同一路径、同一代理,比较默认Expect与显式去除Expect。
- 同一请求,比较直连与代理,确认是代理链还是应用解析问题。
- 固定代理和路径,上传不同大小文件,观察是否在某个大小阈值失败。
每组记录HTTP状态、响应头、服务端解析字段、耗时和实际接收字节。不要用大文件反复压测,也不要把失败重试写成无限循环。
服务端与代理层的修复边界
自有服务可检查上传大小限制、读取超时、multipart解析器和反向代理缓冲配置;代理服务商则应提供请求ID和错误分类。若只有特定第三方接口拒绝上传,应遵守其接口文档,不要通过换IP或伪造头部绕过限制。
验收清单
- Content-Type中的boundary与正文分隔线一致。
- Expect启用/禁用的结果有对照,417和超时被正确归类。
- 入口、代理出口和应用收到的请求体长度可关联。
- 小文件、边界大小和真实业务文件分别验证。
- 日志不包含文件内容、Token、Cookie和代理密码。
文件上传失败的核心是请求体如何被构造、等待和转发。把boundary、Expect、长度和缓冲逐项验证,通常比更换代理出口更快找到原因。






