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协议的一个扩展,它通过交换对象改变的部分而不是完整的对象来优化传输性能。差异编码也是一类实例操控,因为它依赖客户端和服务器之间针对特定的对象实例来交换信息。RFC 3229描述了差异编码。
差异编码的结构,包括请求、生成、接收和装配文档的全过程。客户端必须告诉服务器它有页面的哪个版本,它愿意接受页面最新版的差异(delta),它懂得哪些将差异应用于现有版本的算法。服务器必须检查它是否有这个页面的客户端现有版本,计算客户端现有版本与最新版之间的差异(有若干算法可以计算两个对象之间的差异)。然后服务器必须计算差异,发送给客户端,告知客户端所发送的是差异,并说明最新版页面的新标识(ETag),因为客户端将差异应用于其老版本之后就会得到这个版本。
客户端在If-None-Match首部中使用的是它所持有页面版本的唯一标识,这个标识是服务器之前响应客户端时在ETag首部中发送的。客户端是在对服务器说:“如果你那里页面的最新版本标识和这个ETag不同,就把这个页面的最新版本发给我。”如果只有If-None-Match首部,服务器将会把该页面的最新版本完整地发给客户端。(假设最新版和客户端持有的版本不同。)
不过,如果客户端想告诉服务器它愿意接受该页面的差异,只要发送A-IM首部就可以了。A-IM是Accept-Instance-Manipulation(接受实例操控)的缩写。形象比喻的话,客户端相当于这样说:“哦对了,我能接受某些形式的实例操控,如果你会其中一种的话,就不用发送完整的文档给我了。”在A-IM首部中,客户端会说明它知道哪些算法可以把差异应用于老版本而得到最新版本。服务端发送回下面这些内容:一个特殊的响应代码——226 IM Used,告知客户端它正在发送的是所请求对象的实例操控,而不是那个完整的对象自身;一个IM(Instance-Manipulation的缩写)首部,说明用于计算差异的算法;新的ETag首部和Delta-Base首部,说明用于计算差异的基线文档的ETag(理论上,它应该和客户端之前请求里的If-None-Match首部中的ETag相同!)。
实例操控、差异生成器和差异应用器
客户端可以使用A-IM首部说明可以接受的一些实例操控的类型。服务器在IM首部中说明使用的是何种实例操控。不过到底哪些实例操控类型是可接受的呢?它们又是做什么的呢?
服务器侧的“差异生成器”根据基线文档和该文档的最新实例,用客户端在A-IM首部中指明的算法计算它们之间的差异。客户端侧的“差异应用器”得到差异,将其应用于基线文档,得到文档的最新实例。例如,如果产生差异的算法是Unix系统的diff-e命令,客户端就可以用Unix系统中的文本编辑器ed提供的功能来应用差异,因为diff-e <file1> <file2>产生了一系列ed命令来把<file1>转化为<file2>。ed是一个非常简单的编辑器,支持一些命令。在图15-10的例子中,5c说明要删除基线文档的第5行,而chisels.<cr>.说明要添加chisels.,就这么简单。对于更大的改动,会产生更复杂的指令。Unix系统的diff-e算法是对文件进行逐行比较的,这对于文本文件没问题,但并不适合二进制文件。vcdiff算法更强大,对于非文本文件也适用,并且产生的差异比diff-e要小。
差异编码的规范中详细定义了A-IM和IM首部的格式。在这里,我们只要知道这些首部中可以说明多个实例操控(并可以带有相关的质量值)就够了。在返回给客户端之前,文档可以经过多种实例操控,这样可以获得最大程度的压缩。例如,用vcdiff算法产生的差异随后可以再用gzip算法压缩。于是服务器的响应中就含有IM:vcdiff, gzip首部。客户端应当先对内容进行gunzip,再把得到的差异应用到自己的基线页面上,这样才能生成最终的文档。
总结
差异编码可以减少传输次数,但实现起来可能比较麻烦。设想一下页面改动频繁,而且有很多不同的人都在访问的情形。支持差异编码的服务器必须保存页面随时间变化的所有不同版本,这样才能指出最新版本与所请求的客户端持有的任意版本之间的差异。(如果文档变化频繁,而且有很多客户端都在请求文档,那它们就会获得文档的不同实例。随后当它们再向服务器发起请求时,它们将请求它们所持有的版本与最新版本之间的差异。为了能够只向它们发送变化的部分,服务器必须保存所有客户端曾经持有过的版本。)要降低提交文档时的延迟时间,服务器必须增加磁盘空间来保存文档的各种旧的实例。实现差异编码所需的额外磁盘空间可能很快就会将减少传输量获得的好处抵消掉。
作者介绍
非职业「传道授业解惑」的开发者叶一一。
《趣学前端》、《CSS畅想》等系列作者。华夏美食、国漫、古风重度爱好者,刑侦、无限流小说初级玩家。
如果看完文章有所收获,欢迎点赞 | 收藏⭐️ | 留言。
- 随机文章
- 热门文章
- 热评文章
- 探索内心:新浪心理测试的深度解析新浪心理测试题
- 探索高量程智商测试 High Range I.Q. Tests (HRIQ):挑战极限,挖掘潜能
- 情商与智商:揭秘你的智慧与情感测你智商高还是情商高还是逆商高
- 探索智商测试:国际标准60题的深入解析智商测试题国际标准免费版
- 爱因斯坦的智力挑战:解开宇宙之谜爱因斯坦的智商是怎么测试的
- 测你的性格最像《传闻中的陈芊芊》中的谁
- Java Spring Boot 电商系统
- 云服务器:数字时代的“弹性算力引擎”
- 心理测试 测试你内心真正的性格