1.概念
浏览器缓存(Brower Caching)是浏览器对之前请求过的文件进行缓存,以便下一次访问时重复使用,节省带宽,提高访问速度,降低服务器压力。
http缓存机制主要在http响应头中设定,响应头中相关字段为Expires、Cache-Control、Last-Modified、Etag。
2.强缓存
浏览器中缓存作用分为两种:一种需要发送HTTP请求,另一种不需要发送。
首先是检查强缓存:强缓存指的是只要浏览器判断缓存没有过期,则直接使用浏览器的本地缓存,决定是否使用缓存的主动性在于浏览器这边。
这个阶段不需要发送HTTP请求,那么如何来检查呢?
在HTTP1.0中,使用Expires,在HTTP1.1中,使用Cache-Control。
2.1 Expires(过期时间)
存在于服务端返回的响应头中,告诉浏览器在这个过期时间之前可以直接从缓存中取数据,无需发送请求,提供的是具体的时间点:
Expires: Wed, 22 Nov 2019 08:41:00 GMT
但是这种方式存在缺陷:服务器时间和浏览器时间可能不一致,导致服务器返回的Expires可能不准确。
2.2 Cache-Control
和Expires的本质不同是通过提供过期时长max-age来控制缓存:
Cache-Control : max-age=3600
- 当浏览器第一次请求访问服务器资源时,服务器会在返回这个资源的同时,在 Response 头部加上 Cache-Control,Cache-Control 中设置了过期时间大小;
- 浏览器再次请求访问服务器中的该资源时,会先通过请求资源的时间与 Cache-Control 中设置的过期时间大小,来计算出该资源是否过期,如果没有,则使用该缓存,否则重新请求服务器;
- 服务器再次收到请求后,会再次更新 Response 头部的 Cache-Control。
Cache-Control还可以提供很多其它属性:
public:客户端和代理服务器都可以缓存。因为一个请求可能要经过不同的代理服务器最后才到达目标服务器,那么结果就是不仅仅浏览器可以缓存数据,中间的任何代理节点都可以进行缓存。
private:只有客户端(浏览器)能缓存
no-cache:跳过强缓存,发送HTTP请求,直接进入协商缓存
no-store:不进行任何缓存
那么,当资源缓存时间超时,强缓存失效该怎么办呢?那就进入到接下来的第二层缓存:协商缓存。
3.协商缓存
当我们在浏览器使用开发者工具的时候,你可能会看到过某些请求的响应码是 304,这个是告诉浏览器可以使用本地缓存的资源,通常这种通过服务端告知客户端是否可以使用缓存的方式被称为协商缓存。
强缓存失效后且浏览器已被服务器告知可以使用协商缓存后,浏览器在HTTP请求头中携带相应的缓存tag来向服务器发送请求,服务器根据这个tag决定是否使用缓存。
再次提醒,协商缓存这两个字段都需要配合强制缓存中 Cache-Control 字段来使用,只有在未能命中强制缓存的时候,才能发起带有协商缓存字段的请求。
缓存tag分为Last-Modified和ETag,两者各有优劣,不存在谁全面占优,与强缓存的两个tag不同。
3.1 If-Modified-Since + Last-Modified(最后修改时间)
在浏览器第一次给服务器发送请求后,服务器会在响应头中加上Last-Modified字段,表示这个响应资源的最后修改时间。
浏览器接收到后,如果再次请求,会在请求头中携带If-Modified-Since字段,这个字段的值也就是服务器传来的最后修改时间。
服务器接收到该字段后,会与服务器中该资源的最后修改时间对比:
- 如果If-Modified-Since早于服务器新的Last-Modified,说明资源更新了,返回新的资源和200
- 否则返回304,资源未更新,告诉浏览器直接使用缓存即可
3.2 If-None-Match + ETag
ETag是服务器根据当前文件内容,给文件生成的唯一标识,当文件内容改动,这个值也改动。服务器同样通过响应头将这个值发送给浏览器。
浏览器接收到ETag的值,会在下次请求时,将这个值作为If-None-Match这个字段的内容,并放到请求头中,然后发给服务器。
服务器接收到该字段后,会与服务器中该资源的ETag对比:
- 如果不一致,说明资源更新了,返回新的资源和200
- 否则返回304,资源未更新,告诉浏览器直接使用缓存即可
3.3 两者对比
1.精确度上,ETag更优:
ETag 是按照内容给资源上标识,因此能准确感知资源的变化。
而Last-Modified有两种情况下不能准确感知资源变化:
- 编辑了资源文件,但是文件内容没有更改,这样也会导致缓存失效
- Last-Modified感知的单位时间是秒,如果文件在1s内改变了多次,则无法识别修改
2.性能上,Last-Modified更优:
Last-Modified仅仅只是记录一个时间点,而 Etag需要根据文件的具体内容生成哈希值。
总而言之,当两种方法都支持时,服务器优先考虑ETag