这篇文章是来记录博主对《图解HTTP》书中知识点进行梳理,作为强化学习。网上对此书非常推崇,博主认为这本书是小白入门计网的绝佳选择。我会捋清书中每一章的知识点,梳理出主要且常用的知识点记录总结。看之前最好结合目录问题看,带着问题读完会书中的知识会更有效果。
HTTP 协议的请求和响应报文中必定包含 HTTP 首部。首部内容为客户端和服务器分别处理请求和响应提供所需要的信息。对于客户端用户来说,这些信息中的大部分内容都无须亲自查看。报文首部由几个字段构成。
HTTP 请求报文
在请求中,HTTP 报文由方法、URI、HTTP 版本、HTTP 首部字段等部分构成。
HTTP 响应报文
在响应中,HTTP 报文由 HTTP 版本、状态码(数字和原因短语)、HTTP 首部字段 3 部分构成。
首部字段传递重要信息
HTTP 首部字段是构成 HTTP 报文的要素之一。在客户端与服务器之间以 HTTP 协议进行通信的过程中,无论是请求还是响应都会使用首部字段,它能起到传递额外重要信息的作用。使用首部字段是为了给浏览器和服务器提供报文主体大小、所使用的语言、认证信息等内容。
接下来就是报文首部的内容了(太多了QAQ),参考了解,不需要死记硬背,下面博主会介绍常用的几个。
hhh,看了上面那么多字段内容是不是头晕了。如果是初学者不建议死记硬背,我们来通过HTTP是如何缓存的来理解上面几个常用的命令。这样我们学起来可以更加牢固轻松。至于为什么选择HTTP缓存来解释呢?(因为博主了解的也不多,并且HTTP缓存也是面试常考的重要内容)
首先先声明缓存是应用程序中很重要的一个概念,在有大量数据交换的应用程序中,我们会采取一些方式将那些实时性要求不高的数据生成副本并存储在某个相对来说可快速到达、访问、获取的仓库,这样在需要这些数据的时候我们直接从这个仓库中获取数据。
HTTP 缓存指的是: 当客户端向服务器请求资源时,会先抵达浏览器缓存,如果浏览器有“要请求资源”的副本,就可以直接从浏览器缓存中提取而不是从原始服务器中提取这个资源。
常见的 HTTP 缓存只能缓存 GET 请求响应的资源,对于其他类型的响应则无能为力,所以后续说的请求缓存都是指 GET 请求。
缓存的好处主要有几点:
当用户开始访问一个网站时,浏览器会从目标服务器获取一些资源用以构建最终的 WEB 页面,比如 css、js、html 等静态文件。
假设我们不采取任何措施,则用户每次访问这个网站都要发起一系列 HTTP 请求,试想,如果这个网站的 pv 达到上百万甚至上千万,会对网站的后台服务器造成多大的压力。
为了尽可能提升网站的性能,HTTP 协议给出了一个优化方案,其大体规则如下图所示:
注意:
如果每次客户端都需要向服务器端询问,因为不清楚本地缓存的内容是否为最新的内容,需要进行协商那么就是协商缓存。
从这里开始就涉及到我们报文首部的内容了。
虽然在上面表格已经说过,但是在这里我在此解释一下这两个字段的含义。
Etag: ETag就是一个URL资源的标识符。
If-None-Match: 和Etag类似的实体标志。
当服务器返回时,可以根据返回内容计算一个hash值或者就是一个数字版本号,具体返回什么值要看服务器的计算策略。然后将它加到response的header里面。
比如 Etag可能这样:ETag: "df551425fcc55e4d42a148795d9f2"
客户端拿到后会将这个ETag和返回值一起存下来,等下次请求时,使用配套的If-None-Match,将这个放到request的header里面。
值可能与Etag一致:If-None-Match: "df551425fcc55e4d42a148795d9f2"
然后服务端拿到请求里面的If-None-Match跟当前版本的ETag比较下:
如果是一样的话,直接返回304,语义为Not Modified,不返回内容(body),只返回header,告诉浏览器直接用缓存。
如果不一样的话,返回200和最新的内容
与ETag配套的还有一个不太常用的request header ----If-Match,这个和前面If-None-Match的语义是相反的。前面If-None-Match的语义是如果不匹配就下载。
Last-Modified: 获取资源的更新日期时间。
If-Modified-Since: 用于确认代理或客户端拥有的本地资源的有效日期。
Last-Modified和If-Modified-Since也是配套使用的,类似于ETag和If-None-Match的关系。只不过ETag放的是一个版本号或者hash值,Last-Modified放的是资源的最后修改时间。Last-Modified是放到response的header里面的,可能长这样:
Last-Modified: Wed, 21 Oct 2000 07:28:00 GMT
而客户端浏览器在使用时,应该将配套的If-Modified-Since放到request的header里面,长这样:
If-Modified-Since: Wed, 21 Oct 2000 07:28:00 GMT
服务端拿到这个头后,会跟当前版本的修改时间进行比较:
当前版本的修改时间比这个晚,也就是这个时间后又改过了,返回200和新的内容
当前版本的修改时间和这个一样,也就是没有更新,返回304,不返回内容,只返回头,客户端直接使用缓存
服务端拿到这个头后,也会跟当前版本的修改时间进行比较:
强制缓存就是知道在某个时间段完全不用去问服务端,直接去用本地缓存的内容就行。
Expires
Expires比较简单,就是服务器response的header带上这个字段:
Expires: Wed, 21 Oct 2000 07:28:00 GMT
然后在这个时间前,客户端浏览器都不会再发起请求,而是直接用缓存资源。
Cache-Control
Cache-Control相对比较复杂,可设置属性也比较多,max-age只是其中一个属性,长这样:
Cache-Control: max-age=20000
max-age 指令
这表示当前资源在20000秒内都不用再请求了,直接使用缓存。
其他常用属性还有:
no-cache:使用缓存前,强制要求把请求提交给服务器进行验证(协商缓存验证)。
no-store:不存储有关客户端请求或服务器响应的任何内容,即不使用任何缓存。
Expires和Cache-Control的优先级
如果在Cache-Control响应头设置了 max-age 或者 s-maxage 指令,那么 Expires 头会被忽略。
这个其实很好理解,协商缓存需要发请求跟服务器协商,强制缓存如果生效,根本就不会发请求。所以这个优先级就是:先判断强制缓存,如果强制缓存生效,直接使用缓存;如果强制缓存失效,再发请求跟服务器协商,看要不要使用缓存。
刚刚上述是一个简单过程,但是事实上的缓存策略还要更复杂一点。下面是一个较为完整的缓存流程:
本文介绍了大致的报文首部内容,并用HTTP缓存为例子介绍报文首部字段内容是如何在报文中发挥着他们的作用。HTTP缓存介绍了大概的流程,并且把HTTP缓存机制分为强制缓存和协商缓存两类,并且从报文字段入手详细说明了其中的区别和流程。