← 中文资源

简体中文版本

HTTP — 分块响应被代理截断

调试中间盒错误处理 Transfer-Encoding 导致的分块响应截断,对比 Content-Length 预期,并修缓冲或流式层。

阅读英文原文

症状

  截断用两条命令量化:直连源站 wc -c 得 10485760(基准真值),经公共路径得 9911478(缺了尾巴)——截断定位在中间路径。再用 curl -v –raw 看帧本身:健康的分块响应以零长度块收尾(最后的孤立 0 加 CRLF);流“就这么停了”——连接关闭、无终止符、无错误——是被中间盒切断的,且当切断时刻恰好对齐某个配置的 proxy_read_timeout 时,那行配置就是自白。改写 Content-Length 的变体更隐蔽:代理声明的体长与实际交付不符,严格客户端失败、宽容客户端静默拿到错误大小的文件。

诊断思路

  先做字节对比定位截断属于哪段路径;再看线上帧结构,缺失终止零块或被改写的 Content-Length 直接显示帧违规;最后查代理缓冲与超时配置——缓冲开启配短读超时会把慢流精确截断在超时边界,截断时长等于配置值就是判决。压缩模块、WAF 检查这类响应体改写器对流中异常字节中止,在源站日志零痕迹地制造同样症状。

根因

  分块传输依赖严格帧协议:带尺寸的块、零长度终止块、可选 trailer。缓冲、重组成超时中断流的中间盒破坏契约——客户端收到提前结束的响应体,有时伴随干净的 TCP 关闭把截断完全藏起来。

修复与验证

  流式路由做范围限定配置:proxy_buffering off 让字节流直通、proxy_read_timeout 3600s 度过慢生产者、HTTP/1.1 透传分帧;源站在长间隙期间保持心跳——每几秒一个注释块或进度块,让空闲超时不对合法慢生成开火;审计路径上所有响应体改写器。验证时流式响应经完整路径与源站输出逐字节一致;接近超时阈值的慢块测试无截断完成。高流量路由上全局关缓冲会把并发成本转嫁给上游 worker——只给需要流式的端点关。

代码示例

$ curl -s https://direct.internal/stream | wc -c
10485760                                  <- ground truth
$ curl -s https://app.example.com/stream | wc -c
9911478                                   <- missing the tail
location /stream/ {
    proxy_buffering off;              # stream through, do not accumulate
    proxy_read_timeout 3600s;         # survive slow producers
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    chunked_transfer_encoding on;     # pass framing through honestly
}