实体和编码

本章主要介绍了http实际传输的货物:实体。以及与实体有关的一些实体首部及原理,当然了还介绍了为了减小带宽所作的一些编码措施和原理(内容编码和传输编码)!

HTTP报文应该具备的功能

为了更好的描述http所传输数据的类型、大小、有效性等,http协议应该为主体提供以下描述信息:

  • 可以被正确的识别(通过Content-Type首部说明媒体格式),以便接收端能够识别并正确处理内容
  • 是最新的(通过实体验证码和缓存过期控制)
  • 符合用户的需要(基于Accept系列的内容协商首部)
  • 在网络上可以快速有效地传输(通过范围请求、差异编码以及其他数据压缩方法)
  • 完整到达、未被篡改(通过传输编码首部和Content-MD5校验和首部)

报文是箱子,实体是货物

实体由实体首部和实体主体组成,实体首部是描述货物信息的,实体主体是原始货物。相关首部如下:

  • Content-Type:实体中所承载对象的类型
  • Content-Length:所传送实体主体的长度或大小,(注意:如果主体采取了内容编码进行压缩,那么它所指的是压缩后的长度或大小,此首部是描述报文主体结束的关键,尤其在持久连接时对多个报文进行正确分段)
  • Content-Language:与所传送对象最相配的人类语言
  • Content-Encoding:对象数据所做的任意变换(比如,压缩)
  • Content-Location:一个备用位置,请求时可通过它来获得对象
  • Content-Range:如果这是部分实体,这个首部说明它是整体的那个部分
  • Content-MD5:实体主体内容的校验
  • Last-Modified:所传输内容在服务器上创建或最后修改的日期时间
  • Expires:实体主句将要失效的日期时间
  • Allow:改资源所允许的各种请求方法,例如,GET和HEAD
  • ETag:这份文档特定实例的唯一验证码,ETag首部没有正式定义为实体首部,但它对许多涉及实体的操作来说,都是一个重要的首部
  • Cache-Control:指出应该如何缓存该文档。和ETag首部类似,Cache-Control首部没有正式定义为实体首部

Content-Length:实体的大小

http的早期版本采用关闭连接的办法来划定报文的结束,但是,没有Content-Length的话,客户端就无法判别到底是报文结束时正常的连接关闭,还是报文传输中由于服务器崩溃而导致的连接关闭。客户端需要通过Content-Length来检测报文截尾。注意这个后果对于缓存是很严重的,可能造成缓存长时间用不完整的内容来响应客户端。

Content-Length与持久连接:拥有Content-Length就能对报文进行正确的分段

内容编码:有时候服务器采用内容编码来压缩实体主体以节省空间,Content-Length描述的是压缩过后的长度或大小。

确定实体主体长度的规则,以下规则,谁先匹配到就用谁:

  • 如果特定的HTTP报文类型中不允许带有主体,那么就忽略Content-Length首部。常见情况有:1XX、204以及304响应,还有HEAD方法的响应。
  • 如果报文中含有描述传输编码的Transfer-Encoding首部,那么实体就应由一个称为“零字节块”的特殊模式结束。
  • 如果报文中,有Content-Length首部而无Transfer-Encoding首部,那么Content-Length就是描述首部的长度。如果有Content-Length首部,同时也有Transfer-Encoding首部,那么就必须忽略Content-Length,因为传输编码会改变实体主体的表示和传输方式(因此可能就会改变传输的字节数)。
  • 如果报文使用了multipart/byteranges(多部分/字节范围)媒体类型,且无Content-Length首部,那么报文长度有报文去自定界。
  • 如果以上规则都不匹配,实体的长度就是关闭连接时所得到的的主体的长度。这个值实际上由服务器关闭连接得到。客户端关闭连接将使服务器无法响应。

实体摘要

虽然http建立在tcp/ip这样的可靠传输协议之上,但是还是有很多原因导致报文在传输过程被修改。发送方可以在生成初始的主体时,生成一个数据的校验和。遮掩接收方就可以通过检查这个校验和来捕获所有意外的实体修改了。

媒体类型和字符集

记住一点:Content-Type首部字段说明了实体主体的MIME类型,其值是标准化的MIME类型,都在互联网号码分配机构中注册。

内容编码

编码过程:

  • 生成原始响应报文,有Content-Type和Content-Length首部。
  • 编码服务器对报文进行编码,编码之后同样拥有Content-Type和Content-Length首部,但是Content-Length可能不同(比如主体被压缩了),同时增加了Content-Encoding首部,这样接收端就知道怎样去解码了。
  • 接收端解码,得到原始报文
  • Accept-Encoding首部:该首部描述了接收端能处理的编码方式

传输编码和分块编码

  • 相关首部:Transfer-Encoding首部告诉接收方自己使用了何种编码。TE首部告诉发送端自己希望收到何种编码。
  • 分块编码:首先分块编码是一种传输编码,其格式大致为:http响应首部块开始,随后就是一系列分块,每个分块包含一个长度值和该分块的数据。长度值是16进制形式并将CRLF与数据分隔开。最后一个块有点特别,它的长度值为0,表示“主体结束”。
  • 分块报文中的拖挂(可选),拖挂中可以包含附带的首部字段,它们的值在报文开始的时候可能是无法确定的(例如,必须要先生成主体的内容)。Content-MD5首部就是一个可以在拖挂中发送的首部。

验证码和新鲜度

相关语法:

  • Expires: 要求客户端和服务器时钟同步。
  • Cache-Control: 其相关参数如下(括号中的值表示用在请求报文还是响应报文):
    • no-cache(请求),在重新向服务器验证之前,不要返回文档的缓存版本
    • no-store(请求),不要返回文档的缓存版本,不要保存服务器的响应
    • max-age(请求),缓存中的文档不能超过指定的试用期
    • max-stale(请求),文档允许过期,但不能超过指令中的指定的过期值
    • min-fresh(请求),文档的试用期不能小于这个指定的时间与它的当前存活时间之和,换句话说,响应必须至少在指定的这段时间之内保持新鲜
    • no-transform(请求),文档在发送之前不允许被转换
    • only-if-cached(请求),只要当文档在缓存中才发送,不要联系原始服务器
    • public(响应),响应可以被任何服务器缓存
    • private(响应),响应可以被缓存,但只能被单个客户端访问,换句话说,就是本地缓存。
    • no-cache(响应),如果该指令伴随一个首部列表的话,那么内容可以被缓存并提供给客户端,但必须先删除所列出的首部,如果没有指定首部,缓存中的副本在没有重新向服务器验证之前不能提供给客户端。
    • no-store(响应),不允许被缓存
    • no-transform(响应),响应在提供给客户端之前不能做任何形式的修改
    • must-revalidate(响应),响应在提供给客户端之前必须重新向服务器验证
    • proxy-revalidate(响应), 共享的缓存在提供给客户端之前必须重新向原始服务器验证,私有的缓存可以忽略这条执行
    • max-age(响应),指定文档可以被缓存的时间以及新鲜度的最长时间
    • s-max-age(响应),指定文档作为共享缓存时的最长使用时间,私有的缓存可以忽略本指令

有条件的请求与验证码,概念如下:

  • 有条件的请求,仅当资源改变时才请求副本,这种特殊请求称为有条件的请求。
  • 验证码,说白一点客户端发送什么条件过去可以获知当前文档不新鲜了,所以常用的验证码就是文档最后修改时间以及实例标记。比如有条件的首部If-Modified-Since测试的是文档实例最后被修改的日期时间,因此我们最后被修改的日期时间就是验证码。

相关首部(括号里面的就是其验证码):

  • If-Modified-Since(Last-Modified):如果在前一条响应的Last-Modified首部中说明的时间之后,资源的版本发生变化,就发送其副本。
  • If-Unmodified-Since(Last-Modified):仅在前一条响应的Last-Modified首部中说明的时间之后,资源的版本没有变化,才发送其副本
  • If-Match(ETag):如果实体的标记与前一次响应首部的ETag相同,就发送该资源的副本
  • If-None-Match(ETag):如果实体的标记与前一次响应首部中的ETag不同,就发送该资源的副本

弱验证码和强验证码:弱验证码不一定能唯一标志资源的一个实例,而强验证码能唯一标志一个文档的实例。例如用文档字节数来验证一个文档是否有改变,可能会出现的情况就是,虽然字节数大小没有变,但是内容确实变了,所以字节数验证码是弱验证码,而资源内容的加密校验和(比如MD5)就是强验证码,因为当文档改变时它总是会改变。注:在ETag首部的值前面加上W/,把其标记为弱验证码,此时只是主体发生显著变化时,才会从服务器取资源。

范围请求

概念:Range允许客户端实际只请求文档的一部分,或者说某个范围。

差异编码

概念:差异编码是HTTP协议的一个扩展,它通过交换对象改变的部分而不是完整的对象来优化传输性能。

相关首部:A-IM(请求)指出接受何种差异编码,IM(响应)指出使用了何种差异编码。

下一节:本章主要讲解了http协议在传输的过程中,如何彼此理解对方发送的内容是采用什么字符集编写的,从而彼此能够进行正确的显示内容!由此介绍了相关的报文首部。