HTTP 分块传输是什么?Transfer-Encoding: chunked 适合什么场景?
简化版
Transfer-Encoding: chunked 是 HTTP/1.1 的分块传输机制,服务器可以在不知道完整响应体长度的情况下,边生成边发送。每个 chunk 前面有长度,最后用长度为 0 的 chunk 表示结束。它和 Content-Length 通常二选一:有固定长度就用 Content-Length,动态生成或流式输出时可以用 chunked。它解决的是传输分帧问题,不等于应用层业务分片。
详细版
分块传输适合动态页面、日志流、接口边计算边返回、大文件代理转发等场景。普通固定响应:
Content-Length: 1024
表示客户端提前知道响应体有 1024 字节。分块响应:
Transfer-Encoding: chunked
4
Wiki
5
pedia
0
客户端按 chunk 读取,直到读到 0 长度块。需要注意,chunked 是 HTTP/1.1 的传输编码,不是压缩编码;压缩通常通过 Content-Encoding: gzip/br 表示。
完整版教学
一、为什么需要分块传输
HTTP 响应体如果长度已知,服务器可以直接发送 Content-Length。但很多场景下,响应体长度一开始并不知道:
- 服务端动态生成内容;
- 后端边查询边输出;
- 代理服务器边从上游读边转发;
- 长连接流式推送部分结果。
这时如果必须等所有内容生成完再算长度,就会增加延迟和内存占用。chunked 允许服务器先发头,再分块发送正文。
二、chunked 的格式长什么样
一个简化的 chunked 响应如下:
HTTP/1.1 200 OK
Transfer-Encoding: chunked
4
Wiki
5
pedia
0
每个块的格式是:
chunk-size\r\n
chunk-data\r\n
最后一个块大小为 0,表示响应体结束。这里的 4 和 5 是十六进制长度,不是十进制文本标号。
三、Content-Length 和 Transfer-Encoding 的关系
Content-Length 表示响应体固定长度。客户端读到指定字节数后就知道响应结束。
Transfer-Encoding: chunked 表示响应体由多个块组成,客户端读到 0 长度块才知道结束。
| 方式 | 是否提前知道总长度 | 结束判断 | 常见场景 |
|---|---|---|---|
| Content-Length | 是 | 读取固定字节数 | 静态文件、固定 JSON |
| chunked | 否 | 读到 0 长度块 | 动态生成、代理转发、流式输出 |
在 HTTP/1.1 中,chunked 是解决“长度未知但要保持连接复用”的关键机制。
四、它和连接复用有什么关系
HTTP/1.1 默认支持连接复用。同一个 TCP 连接上可能连续传多个响应,客户端必须知道一个响应在哪里结束,才能正确读取下一个响应。
如果没有 Content-Length,又不用 chunked,客户端可能只能靠关闭连接来判断响应结束:
响应体结束 = 服务端关闭 TCP 连接
这会破坏连接复用。chunked 通过 0 长度块明确结束位置,让连接可以继续用于后续请求。
五、chunked 不是压缩,也不是业务分页
容易混淆的几个概念:
| 概念 | 作用 |
|---|---|
| Transfer-Encoding: chunked | HTTP 传输层面的分块 |
| Content-Encoding: gzip/br | 内容压缩 |
| Range 请求 | 客户端请求资源的一部分 |
| 业务分页 | 应用层按页返回数据 |
chunked 的每个块只是传输格式的一部分,不代表业务上“一条消息”或“一页数据”。应用协议如果需要消息边界,仍然要自己定义,例如 SSE 的事件格式、JSON Lines 等。
六、代理和网关里的注意点
实际工程里,反向代理、网关、框架都可能改变响应传输方式:
- 上游 chunked,代理可能缓冲后转成
Content-Length; - 上游固定长度,代理压缩后可能变成 chunked;
- 某些网关默认开启响应缓冲,导致流式效果消失;
- 客户端库可能自动解码 chunked,让业务代码感知不到块边界。
如果你在排查“服务端明明边写边 flush,浏览器为什么收不到”,要同时检查应用框架、代理缓冲、压缩和 HTTP 版本。
七、常见误区与追问
- 误区:chunked 是一种压缩算法。 chunked 是传输编码,gzip/br 才是常见内容压缩。
- 误区:使用 chunked 后就不能复用连接。 正好相反,chunked 明确响应结束位置,有利于 HTTP/1.1 连接复用。
- 误区:chunk 大小就是业务消息大小。 chunk 是传输层面的块,不一定对应业务事件或 JSON 对象。
- 误区:Content-Length 和 Transfer-Encoding: chunked 可以随便同时用。 两者语义冲突,实际应避免同时发送。
- 追问:chunked 怎么表示响应结束? 发送一个长度为 0 的 chunk 表示正文结束。
- 追问:为什么动态响应适合 chunked? 因为服务端可以不知道总长度,边生成边发送,降低首字节等待和内存压力。
八、加强记忆
分块传输的核心是:不知道总长度,也能明确响应边界。固定长度用 Content-Length,动态或流式输出用 Transfer-Encoding: chunked;每块先写长度,再写数据,最后用 0 长度块结束。它不是压缩、不是 Range、不是分页。面试回答时把“长度未知、边生成边发送、保持连接复用”这三个关键词说出来就很稳。