TE 说的是「我接受哪些传输编码」,最常见值是 trailers。
它和 Accept-Encoding 长得很像,但一个管传输、一个管内容,而且 TE 是逐跳的。
上一节是来源,这一节是传输协商。它和 6.4.3 那个字段最容易混,这一节专门分清。
一、两件事,两个字段
| 对比项 | Accept-Encoding |
TE |
|---|---|---|
| 管什么 | 内容编码(gzip 压缩正文) | 传输编码(分块、尾块) |
| 作用范围 | 端到端,一路传到最终接收者 | 逐跳,只对相邻两跳有效 |
| 常见值 | gzip、br、deflate |
trailers |
| 响应侧对应 | Content-Encoding |
Transfer-Encoding |
| 记住一句话:压缩是内容的事,切块是传输的事。 | ||
| 前者改的是正文的字节,后者改的是这些字节怎么被切开送出。 | ||
所以 TE 属于 6.2.6 那八个固定的逐跳字段之一,代理处理完必须删掉,不能往下传。 |
二、trailers 这个值的意义
TE: trailers 表示「我读得懂尾块」。服务端据此决定要不要用尾块发信息。
这就把 6.3.5 的 Trailer 和这里串起来了:服务端要不要发尾块,得先看客户端发没发这个 TE。
Demo 里三组:不发 TE 时响应 106 字节、没有 Trailer 首部;
发 TE: trailers 时响应 156 字节、有 Trailer 首部。多出来的 50 字节就是分块开销加那两个尾块。
带 q 值也认:TE: gzip, trailers;q=0.5 里 q 是 0.5,仍然大于 0,所以尾块照发。
要是写 trailers;q=0,就该当成拒绝。
三、为什么它能管传输编码
理论上 TE 还能协商别的传输编码,比如 TE: gzip 表示「你可以先 gzip 再发给我,
但这是在传输层做的,不是内容层」。
但这条几乎没人用。因为传输编码本来是给中间节点用的——代理为了在慢链路上省带宽,可以在转发时压一下。
客户端主动要求这个,收益不大还容易出错。
所以现实里 TE 就等同于 TE: trailers。其他取值都是纸面上的可能性。
四、动手 Demo:三组 TE,看服务端发不发尾块
服务端检查 TE 里有没有 trailers。有就用分块加尾块发,没有就发普通响应。
客户端对比两者的字节数和首部。
te = hd.get(u'te', u'')
if u'trailers' in te.lower():
parts = [u'HTTP/1.1 200 OK',
u'Trailer: X-Sum',
u'Transfer-Encoding: chunked',
u'Connection: close', u'', u'']
out = bytearray(u'\r\n'.join(parts).encode(u'utf-8'))
for seg in (b'aaa\n', b'bbb\n'):
out += (u'%x\r\n' % len(seg)).encode() + seg + b'\r\n'
out += b'0\r\nX-Sum: 8\r\n\r\n'
return bytes(out)
实跑输出:
--------------------------------------------------------------------
TE:我能接受哪些传输编码(逐跳)
--------------------------------------------------------------------
【不发 TE】
TE (没发)
服务端做法 普通响应,不带尾块
响应有没有 Trailer 首部 没有
响应字节数 106
【TE: trailers】
TE trailers
服务端做法 带尾块
响应有没有 Trailer 首部 有
响应字节数 156
【TE: gzip, trailers;q=0.5】
TE gzip, trailers;q=0.5
服务端做法 带尾块
响应有没有 Trailer 首部 有
响应字节数 156
`TE` 和 `Accept-Encoding` 长得很像,但管的是两件事:
**`Accept-Encoding` 管内容编码**(gzip 压缩正文),是端到端的;
**`TE` 管传输编码**(分块、以及能不能接受尾块),是逐跳的。
所以 `TE` 属于 6.2.6 那八个固定的逐跳字段之一,代理必须处理掉。
它最常见的值就是 `trailers`:告诉服务端「我读得懂尾块」。
服务端据此决定要不要用尾块发校验和——
也就是说 6.3.5 那个 Trailer 要不要出现,得先看客户端发没发这个 TE。
不发 TE:普通响应,106 字节,「响应有没有 Trailer 首部」是「没有」。
发 TE: trailers:156 字节,有 Trailer 首部,正文用分块传输。
发 TE: gzip, trailers;q=0.5:同样 156 字节,同样带尾块。q=0.5 仍然表示接受。
多出来的 50 字节是分块开销加尾块。
所以尾块不是免费的——只有确实需要「发完才知道」的信息时,才值得用它。
30 秒实验
- 发
TE: trailers;q=0,看服务端该不该发尾块。 - 发
TE: gzip,看服务端会不会把正文 gzip 后放传输层(本 Demo 不会)。 - 想一想:为什么
TE是逐跳的,而Accept-Encoding是端到端的?
常见误区
- 「
TE和Accept-Encoding是一回事」——一个管传输编码,一个管内容编码。 - 「
TE是端到端的」——是逐跳的,代理必须处理掉。 - 「
TE能协商任意压缩算法」——理论上可以,实际只用trailers。
自测三问(点开对答案)
1. `TE` 和 `Accept-Encoding` 的分工是什么? —— `Accept-Encoding` 管内容编码(gzip 正文),`TE` 管传输编码(分块、尾块)。 2. `TE: trailers` 是什么意思? —— 我读得懂尾块,你可以用尾块给我发信息。 3. 为什么 `TE` 是逐跳字段? —— 传输编码只对相邻两跳之间的这一条连接有意义,换一条连接就失效了。19 个请求首部只剩最后一个:客户端的自我介绍。
- ☐ (本节完,下一节 6.4.19 User-Agent)