强缓存与协商缓存
浏览器缓存其实是http缓存,主要是通过http请求头或响应头中的某些字段控制的
在这篇文章中,讲解了http请求发起到响应的整体过程,流程图大概如下
第一次发起http请求的时候,浏览器会首先去缓存中查找是否有该请求的资源,没有的话才会真正的去服务器请求。
强缓存
与强缓存有关的http响应头字段为Cache-Control
、Expires
, 如果响应头中同时包含这两个字段,那么Cache-Control
的优先级要高于Expires
Cache-Control
Cache-Control
是HTTP/1.1
中的重要规则,主要用于控制网页缓存,主要有以下几个属性
- public: 所有内容都可以缓存(客户端和代理服务器都可以缓存)
- private: 所有内容只有客户端可以缓存(默认值)
- no-cache: 客户端缓存内容,但每次使用之前都必须去服务器验证缓存是否过期,是否有最新版本
- no-store: 不允许缓存
- must-revalidate: 缓存如果没过期就可以继续使用,过期还想用必须去服务器验证
- max-age: 缓存在xxx秒后过期
Expires
Expires
是HTTP/1.0
中控制网页缓存的字段,其值为服务器返回该请求结果缓存的到期时间,当再次发起该请求时,如果客户端的时间小于Expires
时,直接使用缓存。
但Expires
是存在问题的,当客户端和服务器端的时间不一致时,例如客户端自己调整过时间或者时区不一致,可能会导致强制缓存失效。
协商缓存
当强缓存失效以后,就会启用协商缓存,与协商缓存有关的响应头字段为Last-Modified
和ETag
, 请求头字段为If-Modified-Since
、If-None-Match
, 当响应头中同时包含这两个字段时,ETag
字段优先级大于Last-Modified
Last-Modified/If-Modified-Since
Last-Modified
是服务器响应请求时, 返回该资源在服务器上最后的修改时间, 当客户端再次发起该请求时, 会在请求头上带上If-Modified-Since
字段,值为上次请求返回的Last-Modified
的值。通过此字段是为了告诉服务器上次请求时该资源的最后修改时间。服务器接收到该请求后,发现有If-Modified-Since
字段,则会读取该字段与服务器上该资源最后修改时间做对比,如果相等,则状态码返回304,告诉客户端可以继续用缓存里的资源,并更新一下缓存有效期,否则,状态码返回200, 并返回最新资源以及重新存入缓存。
但是这两个字段判断缓存也是有问题的
- 文件非内容的修改,这个时候我们并不希望客户端认为这个文件修改了,从而重新请求
- 某些文件修改的特别频繁,1s内修改好几次,
If-Modified-Since
能检查的时间粒度是秒级的,这种修改无法判断 - 某些服务器不能精确的得到文件的最后修改时间
ETag/If-None-Match
为了解决上述问题, 所以HTTP/1.1
才会增加了ETag/If-None-Match
两个字段
ETag
是服务返回请求时,响应头中所携带的字段,代表该资源的一个唯一标识符(由服务器生成),当文件内容修改以后,该值就会发生变化,类似使用MD5、SHA
等生成的唯一标识符。
当客户端再次发起该请求时,会在请求头中携带If-None-Match
字段,该字段的值为上次请求时ETag
的值,当服务器接收到该请求时,发现请求头中有If-None-Match
字段,会自动读取该字段,与服务器上该资源的唯一标识符进行比较,如果相等,则状态码返回304,告诉客户端缓存还可以用,浏览器会更新缓存有效期,否则返回200, 重新返回最新资源,并重新缓存。
总结
强缓存优先级大于协商缓存,当强缓存有效时,直接使用缓存里的资源加载页面,如果强缓存失效,则启用协商缓存,协商缓存是由服务器决定缓存是否有效的,如果服务器判断缓存有效,会返回状态码304,告诉客户端可以继续使用缓存,否则,状态码为200, 并返回最新资源。