深度解秘HTTP通信细节 (10)

当上面两个字段暗示的过期时间已到,需要向服务器再次验证文档的新鲜度。如果这时缓存仍和服务器上的原始文档一致,缓存只需要更新头部的相关字段。

为了更好的节省网络流量,缓存服务器可以通过相关首部向原始服务器发送一个条件GET请求, 这样只有在缓存真正过期的情况下,才会返回原始的文档,否则只会返回相关的首部。条件GET请求会用到如下的字段:

缓存条件GET

cookie

cookie是服务器“贴在”客户端身上的标签,由客户端维护的状态片段,并且只会回送给合适的站点。

有两类cookie: 会话cookie、持久cookie. 会话cookie在退出浏览器后就被删除了;而持久cookie则保存在硬盘中,计算机重启后仍然存在。

服务器在给客户端的响应字段首部加上Set-cookie或Set-cookie2, 值为名字=值的列表,即可以包含多个字段。当下次浏览器再次访问到相同的网站时,会将这些字段通过Cookie带上。cookie中保留的内容是服务器给此客户端打的标签,方便服务进行追踪的识别码。浏览器会将cookie以特定的格式存储在特定的文件中。

浏览器只会向产生这条cookie的站点发生cookie. Set-cookie字段的值会包含domain这个字段,告知浏览器可以把这条cookie发送给给相关的匹配的站点。path字段也是相似的功能。如i浏览器收到如下的cookie:

Set-cookie: user="mary"; domain="stefno.com"

那么浏览器在访问任意以stefno.com结尾的站点都会发送:

Cookie: user="mary" 实体和编码

响应报文中的body部分传输的数据本质上都是二进制。我们从上面的报文数据也可以看出来,都是用十六进制数来表示,关键是怎么解释这块内容。如果Content-Type定义是text/plain, 那说明body内容就是文本,我们直接按文本编码来解释;如果Content-Type定义是image/png, 说明body部分是一幅图片,那我们就按图片的格式去解释数据。

Content-Length标示报文主体部分的数据长度大小,如果内容是压缩的,那它表示的就是压缩后的大小。另外,Content-Length在长连接的情况下,可以对多个报文进行正确地分段。所以,如果没有采用分块编码,响应数据中必须带上Content-Length字段。分块编码的情形中,数据被拆分成很多小块,每块都有大小说明。因此,任何带有主体部分的报文(请求或是响应)都应带上正确的Content-Length首部。

HTTP的早期版本采用关闭连接的方式来划定报文的结束。这带来的问题是显而易见的:客户端并不能分清是因为服务器正常结束还是中途崩溃了。这里,如果是客户端用关闭来表示请求报文主体部分的结束,是不可取的,因为关闭之后,就无法获取服务器的响应了。当然,客户端可以采用半关闭的方式,只关闭数据发送方向,但是很多服务器是不识别的,会把半关闭当成客户端要成服务器断开来处理。

HTTP报文在传输的过程中可能会遭到代理或是其他通信实体的无意修改,为了让接收方知道这种情况,服务器会对body部分作一个md5, 并把值放到Content-MD5这个字段中。但是,如果中间的代理即修改了报文主体,又修改了md5, 就不好检测了。因此规定代理是不能修改Content-MD5首部的。这样,客户端在收到数据后,先进行解码,再算出md5, 并与Content-MD5首部进行比较。

HTTP在发送内容之前需要对其进行编码,它是对报文主体进行的可逆变换。比如将报文用gzip格式进行压缩,减少传输时间。常见的编码类型如下:

编码类型

当然,客户端为了避免服务器返回自己不能解码的数据,请求的时候,会在Accept-Encoding首部里带上自己支持的编码方式。如果不传输的话,默认可以接受任何编码方式。

上面提到的编码是内容编码,它只是在响应报文的主体报文将原始数据进行编码,改变的是内容的格式。还有另一种编码:传输编码。它与内容无关,它是为了改变报文数据在网络上传输的方式。传输编码是在HTTP 1.1中引入的一个新特性。

通常,服务器需要先生成数据,再进行传输,这时,可以计算数据的长度,并将其编码到Content-Length中。但是,有时,内容是动态生成的,服务器希望在数据生成之前就开始传输,这时,是没有办法知道数据大小的。这种情况下,就要用到传输编码来标注数据的结束的。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpywyy.html