Nginx正确透传分块传输编码需关闭proxy_buffering off、强制HTTP/1.1、清除Connection头、避免Content-Length与Transfer-Encoding共存,并禁用后端及Nginx自身压缩。

要让 Nginx 正确处理后端返回的分块传输编码(Chunked Transfer Encoding),关键不是“开启”它,而是确保不破坏它——Nginx 默认能透传 chunked 响应,但默认配置会主动拦截、缓冲、重写,导致 chunked 消失或报错 ERR_INCOMPLETE_CHUNKED_ENCODING。
必须关闭代理响应缓冲
这是最核心的一条。Nginx 默认启用 proxy_buffering on,它会等后端把整个响应发完,再计算长度、添加 Content-Length、去掉 Transfer-Encoding: chunked。结果就是:后端明明在流式输出,客户端却收到一个带 Content-Length 的完整响应,甚至直接中断。
- 务必在对应
location中显式写:proxy_buffering off; - 关掉后,Nginx 改为边收边发,原始 chunk 头(如
1a\r\n...)和数据会原样透传 - 注意:
proxy_buffering off与gzip on冲突,压缩将失效;也无法使用proxy_intercept_errors
强制使用 HTTP/1.1 并清理连接头
HTTP/1.0 不支持 chunked,如果 Nginx 与后端协商成 1.0,就会自动丢弃 chunked 头并加 Connection: close,导致流式中断。
- 设置:proxy_http_version 1.1;(默认是 1.0,必须显式覆盖)
- 清除可能干扰的连接控制头:proxy_set_header Connection '';
- 若后端也依赖 keep-alive,可额外加:
proxy_set_header Connection 'keep-alive';,但多数流式场景用空字符串更稳妥
避免内容长度冲突与非法头组合
只要响应中同时出现 Content-Length 和 Transfer-Encoding: chunked,就是 HTTP 协议非法组合。Nginx 会优先信任 Content-Length,直接忽略 chunked,甚至截断响应。
- 检查后端代码:不要手动设置
Content-Length,尤其使用json.Encoder、StreamingResponse、yield等流式方式时 - 禁用后端自动压缩中间件(如 Express 的
compression()、FastAPI 的默认 gzip),它们会预读全部响应再编码,破坏流式 - Nginx 自身的
gzip on在proxy_buffering off下不生效,无需特别关,但建议显式关掉以避免混淆
辅助优化与验证方法
配置生效后还需验证是否真正在流式传输,不能只看响应头有没有 Transfer-Encoding: chunked。
- 用
curl -v http://your-domain/stream观察原始响应流,确认能看到类似1a\r\n{...}\r\n这样的分块标记行 - 检查 Nginx error log,排除
upstream sent no valid HTTP/1.1 header类警告 - 可选调优:
proxy_buffer_size 4k;和proxy_buffers 8 4k;设小些,减少首字节延迟,但不必过度调低 -
chunked_transfer_encoding指令对 proxy_pass 完全无效,删掉它,别放在 location 里占地方


















