4月阅读周·HTTP权威指南:实体和编码之传输编码和分块编码篇
引言
HTTP(Hypertext Transfer Protocol,超文本传输协议)是在万维网上进行通信时所使用的协议方案。HTTP有很多应用,但最著名的是用于Web浏览器和Web服务器之间的双工通信。
《HTTP权威指南》一书将HTTP中一些互相关联且常被误解的规则梳理清楚,并编写了一系列基于各种主题的章节介绍HTTP各方面的特性。纵观全书,对HTTP“为什么”这样做进行了详细的解释,而不仅仅停留在它是“怎么做”的。此外,这本书还介绍了很多HTTP应用程序正常工作所必需且重要的非HTTP技术。
这本书主要包括以下内容:
- 第一部分描述了Web的基础构件与HTTP的核心技术
- 第二部分重点介绍了Web系统的结构构造块:HTTP服务器、代理、缓存、网关以及机器人应用程序。
- 第三部分提供了一套用于追踪身份、增强安全性以及控制内容访问的技术和技巧。
- 第四部分涵盖HTTP报文主体和Web标准,前者包含实际内容,后者描述并处理主体内容。
- 第五部分介绍了发布和传播Web内容的技巧。
- 第六部分是一些很有用的参考附录,以及相关技术的教程。
实体和编码
每天都有数以亿计的各种媒体对象经由HTTP传送,如图像、文本、影片以及软件程序等。只要你能叫出名字,HTTP就可以传送。HTTP还会确保它的报文被正确传送、识别、提取以及适当处理。
主要包括以下内容:
- 作为HTTP数据的容器,HTTP报文实体有哪些格式和行为。
- HTTP如何描述实体的主体大小,HTTP为确定大小制定了哪些规则。
- 为了使客户端正确处理内容,使用了哪些实体首部来描述内容的格式、字母和语言。
- 可逆的内容编码,发送方可以在发送之前用它来转换内容的数据格式,使其占用更小的空间,或者更安全。
- 传输编码和分块编码。传输编码可以改变HTTP传输数据的方式,以改善某些类型内容的通信能力。分块编码是一种特殊的传输编码,它把数据切分为若干块,这样可以更可靠地传输长度未知的内容。
- 标记、标签、时间以及校验和等一整套机制,帮助客户端获取所请求内容的最新版本。
- 可用作内容版本号的验证码,网站应用可以通过它确保接收最新的内容。还有设计用来控制对象新鲜度的各种HTTP首部字段。
- 范围,在恢复中断的传输方面很有用。
- HTTP差异编码扩展,它使客户端只需要请求网页中和前一次相比有改变的部分。
- 实体主体的校验和,可以用来检测经过若干代理之后,实体的内容是否发生了改变。
传输编码和分块编码
可靠传输
长久以来,在其他一些协议中会用传输编码来保证报文经过网络时能得到“可靠传输”。在HTTP协议中,可靠传输关注的焦点有所不同,因为底层的传输设施已经标准化并且容错性更好。在HTTP中,只有少数一些情况下,所传输的报文主体可能会引发问题。其中两种情况如下所述。
- 未知的尺寸:如果不先生成内容,某些网关应用程序和内容编码器就无法确定报文主体的最终大小。通常,这些服务器希望在知道大小之前就开始传输数据。因为HTTP协议要求Content-Length首部必须在数据之前,有些服务器就使用传输编码来发送数据,并用特别的结束脚注表明数据结束。
- 安全性:你可以用传输编码来把报文内容扰乱,然后在共享的传输网络上发送。不过,由于像SSL这样的传输层安全体系的流行,就很少需要靠传输编码来实现安全性了。
Transfer-Encoding首部
HTTP协议中只定义了下面两个首部来描述和控制传输编码。
- Transfer-Encoding:告知接收方为了可靠地传输报文,已经对其进行了何种编码。
- TE:用在请求首部中,告知服务器可以使用哪些传输编码扩展。
下面的例子中,请求使用了TE首部来告诉服务器它可以接受分块编码(如果是HTTP/1.1应用程序的话,这就是必须的)并且愿意接受附在分块编码的报文结尾上的拖挂:
GET /new_products.html HTTP/1.1
Host: www.joes-hardware.com
User-Agent: Mozilla/4.61 [en] (WinNT; I)
TE: trailers, chunked
...
对它的响应中包含Transfer-Encoding首部,用于告诉接收方已经用分块编码对报文进行了传输编码:
HTTP/1.1200 OK
Transfer-Encoding: chunked
Server: Apache/3.0
...
在这个起始首部之后,报文的结构就将发生改变。
传输编码的值都是大小写无关的。HTTP/1.1规定在TE首部和Transfer-Encoding首部中使用传输编码值。最新的HTTP规范只定义了一种传输编码,就是分块编码。与Accept-Encoding首部类似,TE首部也可以使用Q值来说明传输编码的优先顺序。不过,HTTP/1.1规范中禁止将分块编码关联的Q值设为0.0。
HTTP将来的扩展可能会推动对更多传输编码的需求。如果真的如此,那分块编码仍应始终作用在其他传输编码之上,这样就保证数据可以像隧道那样“穿透”那些只理解分块编码但不理解其他传输编码的HTTP/1.1应用程序。
分块编码
分块编码把报文分割为若干个大小已知的块。块之间是紧挨着发送的,这样就不需要在发送之前知道整个报文的大小了。要注意的是,分块编码是一种传输编码,因此是报文的属性,而不是主体的属性。本章前面部分讨论过的多部分编码,就是主体的属性,它和分块编码是完全独立的。
1.分块与持久连接
若客户端和服务器之间不是持久连接,客户端就不需要知道它正在读取的主体的长度,而只需要读到服务器关闭主体连接为止。
当使用持久连接时,在服务器写主体之前,必须知道它的大小并在Content-Length首部中发送。如果服务器动态创建内容,就可能在发送之前无法知道主体的长度。
分块编码为这种困难提供了解决方案,只要允许服务器把主体逐块发送,说明每块的大小就可以了。因为主体是动态创建的,服务器可以缓冲它的一部分,发送其大小和相应的块,然后在主体发送完之前重复这个过程。服务器可以用大小为0的块作为主体结束的信号,这样就可以继续保持连接,为下一个响应做准备。
分块编码是相当简单的。一个分块编码报文的基本结构,它由起始的HTTP响应首部块开始,随后就是一系列分块。每个分块包含一个长度值和该分块的数据。长度值是十六进制形式并将CRLF与数据分隔开。分块中数据的大小以字节计算,不包括长度值与数据之间的CRLF序列以及分块结尾的CRLF序列。最后一个块有点特别,它的长度值为0,表示“主体结束”。
客户端也可以发送分块的数据给服务器。因为客户端事先不知道服务器是否接受分块编码(这是因为服务器不会在给客户端的响应中发送TE首部),所以客户端必须做好服务器用411 Length Required(需要Content-Length首部)响应来拒绝分块请求的准备。
2.分块报文的拖挂
如果客户端的TE首部中说明它可以接受拖挂的话,就可以在分块的报文最后加上拖挂。产生原始响应的服务器也可以在分块的报文最后加上拖挂。拖挂的内容是可选的元数据,客户端不一定需要理解和使用(客户端可以忽略并丢弃拖挂中的内容)。
拖挂中可以包含附带的首部字段,它们的值在报文开始的时候可能是无法确定的(例如,必须要先生成主体的内容)。Content-MD5首部就是一个可以在拖挂中发送的首部,因为在文档生成之前,很难算出它的MD5。图15-6中展示了拖挂的使用方式。报文首部中包含一个Trailer首部,列出了跟在分块报文之后的首部列表。在Trailer首部中列出的首部就紧接在最后一个分块之后。
除了Transfer-Encoding、Trailer以及Content-Length首部之外,其他HTTP首部都可以作为拖挂发送。
传输编码的规则
对报文主体使用传输编码时,必须遵守以下规则。
- 传输编码集合中必须包括“分块”。唯一的例外是使用关闭连接来结束报文。
- 当使用分块传输编码时,它必须是最后一个作用到报文主体之上的。
- 分块传输编码不能多次作用到一个报文主体上。
这些规则使得接收方能够确定报文的传输长度。传输编码是HTTP 1.1版中引入的一个相对较新的特性。实现传输编码的服务器必须特别注意不要把经传输编码后的报文发送给非HTTP/1.1的应用程序。同样地,如果服务器收到无法理解的经过传输编码的报文,它应当用501 Unimplemented状态码来回复。不过,所有的HTTP/1.1应用程序至少都必须支持分块编码。
总结
内容编码,是对报文的主体进行的可逆变换。内容编码是和内容的具体格式细节紧密相关的。例如,你可能会用gzip压缩文本文件,但不是JPEG文件,因为JPEG这类东西用gzip压缩的不够好。
传输编码。传输编码也是作用在实体主体上的可逆变换,但使用它们是由于架构方面的原因,同内容的格式无关。使用传输编码是为了改变报文中的数据在网络上传输的方式。
作者介绍
非职业「传道授业解惑」的开发者叶一一。
《趣学前端》、《CSS畅想》等系列作者。华夏美食、国漫、古风重度爱好者,刑侦、无限流小说初级玩家。
如果看完文章有所收获,欢迎点赞👍 | 收藏⭐️ | 留言📝。
- 点赞
- 收藏
- 关注作者
评论(0)