HTTP协议(HyperText Transfer Protocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传输协议。
当你在浏览器的地址框中输入一个URL(www.baidu.com)或是单击一个超级链接时,URL就确定了要浏览的地址。浏览器通过超文本传输协议(HTTP),将Web服务器上站点的网页代码提取出来,并翻译成漂亮的网页。
我们需要获取到服务器上的资源或者请求服务器的接口,都要发送请求(不一定必须是http请求)。
客户端发送一个HTTP请求到服务器的请求消息包括以下格式:请求行(request line)、请求头部(header)、空行和请求数据四个部分组成。

GET /hello.txt HTTP/1.1
User-Agent: curl/7.16.3 libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3
Host: www.example.com
Accept-Language: en, mi
常用请求方法:

HTTP响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文。

在浏览器加载资源的时候,首先会根据请求头的expires和cache-control判断是否命中强缓存策略,判断是否向远程服务器请求资源还是去本地获取缓存资源。
在浏览器中,强缓存分为Expires(http1.0规范)、cache-control(http1.1规范)两种。
Expires是http1.0的规范,用于表示资源的过期时间的请求头字段,值是一个绝对时间(到期时间),是由服务器端返回的。
在浏览器第一个请求资源时,服务器端的响应头会附上Expires这个响应字段,当浏览器在下一次请求这个资源时会根据上次的expires字段是否使用缓存资源(当请求时间小于服务端返回的到期时间,直接使用缓存数据)
注意:
expires是根据本地时间来判断的,假设客户端和服务器时间不同,会导致缓存命中误差
Expires有个缺点,当客户端本地时间和服务器时间不一致时会产生误差,浏览器会直接向服务器请求新的资源,为了解决这个问题,在http1.1规范中,提出了cache-control字段,且这个字段优先级高于上面提到的Expires,值是相对时间。
cache-control中有常见的几个响应属性值:

例如下面是一张图片的响应:

强缓存都是由本地浏览器确定是否使用缓存,当浏览器没有命中强缓存时就会向浏览器发送请求,验证协商缓存是否命中,如果缓存命中则返回304状态码,否则返回新的资源数据。
同样,协商缓存的标识也是在响应报文的HTTP头和请求结果一起返回给浏览器的,控制协商缓存的字段分别有:
其中Etag/If-None-Match优先级比Last-Modified/If-Modified-Since高。

Last-Modified是服务器响应请求时,返回该资源文件在服务器最后被修改的时间。
If-Modified-Since则是客户端再次发起该请求时,携带上次请求返回的Last-Modified值,通过此字段告诉服务器该资源上次请求返回的最后被修改时间。服务器收到该请求,发现请求头含有If-Modified-Since字段,则会根据If-Modified-Since的字段值与该资源在服务器的最后被修改时间做对比:
Etag是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成)。
If-None-Match是客户端再次发起请求时,携带上次请求返回的唯一标识Etag值,服务端收到该请求后,发现该请求含有If-None-Match,则会根据If-None-Match的字段值与该资源在服务器的Etag值做对比:
所以协商缓存结果:
了解了强缓存和协商缓存,那么我们可以大概描述一下一次完整的请求流程:
强缓存是否存在(cache-control优先于expires),如果强缓存的时间没有过期则返回本地缓存资源(状态码为200)。协商缓存策略,首先服务器判断Etag标识符,如果客户端传来标识符和当前服务器上的标识符是一致的,则返回状态码 304 not modified(不会返回资源内容)。if-modified-match和服务器上资源的最后修改时间,如果这两个值是一致的,此时响应头不会带有last-modified字段(因为资源没有变化,last-modified的值也不会有变化),客户端304状态码之后读取本地缓存。如果If-Modified-Since的字段值与该资源在服务器的最后被修改时间不一样,那么返回新资源,状态码为200。简化:
强缓存->(cache-control > expires) [强缓存失败] -> 协商缓存 -> (Etag > last-modified) -> [协商缓存失败] -> 重新获取资源