目录

304 状态码

先上一张 HTTP 请求流程图:

https://github.com/WangYuLue/pic_of_blog/blob/master/1711/28.png?raw=true

一、详细讨论

1、是否禁止缓存

禁止缓存指的是缓存中不得存储任何关于客户端请求和服务端响应的内容。每次由客户端发起的请求都会下载完整的响应内容。

在请求头中,Cache-Control: no-storePragma: no-cache都可以禁止缓存,

但两者也有区别,Pragma: no-cache可以兼容http 1.0 ,而Cache-Control: no-storehttp 1.1提供的。因此,Pragma: no-cache可以应用到http 1.0http 1.1,而Cache-Control: no-store只能应用于http 1.1

2、是否检查本地副本是否过期

是否检查本地版本是否过期主要由Cache-Controlno-cachemust-revalidate这两个可选值控制,其中:

  • no-cache: 告诉浏览器、缓存服务器,不管本地副本是否过期,使用资源副本前,一定要到源服务器进行副本有效性校验。
  • must-revalidate:告诉浏览器、缓存服务器,本地副本过期前,可以使用本地副本;本地副本一旦过期,必须去源服务器进行有效性校验。

3、本地副本是否过期

想要知道本地副本是否过期,我们就需要了解缓存的过期机制

(1)、过期机制中,最重要的指令是 max-age=<seconds>,它表示资源能够被缓的最大时间;它通常会和must-revalidate一起使用,使用起来就像下面这样:

1
Cache-Control: max-age=60, must-revalidate

(2)、如果不含有max-age属性,则会去查看是否包含Expires属性,通过比较Expires的值和头里面Date属性的值来判断是否缓存还有效。

https://github.com/WangYuLue/pic_of_blog/blob/master/1711/20.png?raw=true

(3)、如果 max-ageexpires 属性都没有,找找头里的 Last-Modified 信息。如果有,缓存的寿命就等于头里面 Date的值减去Last-Modified的值除以 10(注:根据 rfc2626 其实也就是乘以 10%)。

https://github.com/WangYuLue/pic_of_blog/blob/master/1711/21.png?raw=true

4、如果本地副本没有过期

如果本地副本没有过期,则会直接重缓存中读取资源,并返回 200 状态码。

https://github.com/WangYuLue/pic_of_blog/blob/master/1711/22.png?raw=true

5、如果本地副本过期

如果本地副本过期,则会进行到源服务器进行有效性校验的前期准备

首先,会在请求头里寻找If-None-Match字段,其值为服务器上次返回的ETag响应头的值:

https://github.com/WangYuLue/pic_of_blog/blob/master/1711/23.png?raw=true

https://github.com/WangYuLue/pic_of_blog/blob/master/1711/27.png?raw=true

如果请求头里没有If-None-Match字段,则会在请求头中寻找If-Modified-Since字段,其值为服务器上次返回的Last-Modified响应头中的日期值:

https://github.com/WangYuLue/pic_of_blog/blob/master/1711/24.png?raw=true

https://github.com/WangYuLue/pic_of_blog/blob/master/1711/25.png?raw=true

如果If-None-MatchIf-Modified-Since都没有,则会直接向服务器请求数据。

6、到源服务器进行有效性校验

如果请求头中带有If-None-MatchIf-Modified-Since,则会到源服务器进行有效性校验,如果源服务器资源没有变化,则会返回 304;如果有变化,则返回 200;

7、上述的一些流程还可以用下图来表示

https://github.com/WangYuLue/pic_of_blog/blob/master/1711/26.png?raw=true

二、补充

私有缓存和公共缓存

Cache-Control还有两个值:privatepublic,其中:

public 指令表示该响应可以被任何中间人(比如中间代理、CDN 等)缓存。若指定了 public ,则一些通常不被中间人缓存的页面(因为默认是 private)(比如 带有 HTTP 验证信息(帐号密码)的页面 或 某些特定影响状态码的页面),将会被其缓存。

private 则表示该响应是专用于某单个用户的,中间人不能缓存此响应,该响应只能应用于浏览器私有缓存中。