一、什么是web缓存
缓存是一种保存资源副本并在下次请求时直接使用该副本的技术。当 web 缓存发现请求的资源已经被存储,它会拦截请求,返回该资源的拷贝,而不会去源服务器重新下载。
Web 缓存能够减少延迟与网络阻塞,进而减少显示某个资源所用的时间。借助 HTTP 缓存,Web 站点变得更具有响应性。接下来的内容中我们将通过web缓存位置、缓存策略以及实际场景应用缓存策略来探讨浏览器缓存机制。
二、缓存位置
上图是第二次打开某个网页的Network资源请求图,可以看到一些资源是直接从浏览器缓存读取了数据,具体表现在: status栏为灰色的200;Size栏显示灰色的memory cache (内存缓存)和 disk cache(硬盘缓存)。
那么内存缓存和硬盘缓存有什么区别呢?
内存缓存(from memory cache):特点是容量小、快速读取、时效性。
内存缓存是将编译解析后的文件,直接存入该进程的内存中,占据该进程一定的内存资源,容量小,但可以保证下次使用缓存资源时的快速读取,然鹅一旦该进程关闭,该进程的内存则会清空。
硬盘缓存(from disk cache):特点是容量大、读取缓慢、持续性长。
硬盘缓存则直接将资源写入硬盘文件中,读取缓存需要对该缓存存放的硬盘文件进行I/O操作,然后重新解析该缓存内容,读取复杂,速度比内存缓存慢。
在内存使用率低,缓存小尺寸资源时,会优先使用内存缓存;反之,在内存使用率高,缓存大尺寸资源时,会优先使用硬盘缓存。
三、缓存规则
浏览器端和服务端的缓存规则,主要在http协议头中定义。
与缓存有关的http消息报头有:Expires,Pragma,Cache-Control,Last-modified,If-Modified-Since,Etag,If-None-Match。
1、强制缓存策略
当浏览器发起 HTTP 请求时,会依次查找上述缓存位置中是否存在缓存资源并通过缓存标识字段 Expires 或 Cache-Control 来验证缓存资源是否过期。
Expires:HTTP 1.0 缓存控制响应头,缓存过期时间,用来指定资源到期的时间,是服务器端的具体的时间点。
Cache-Control:HTTP 1.1 缓存控制响应头,是服务器端在响应请求时用来规定资源是否需要被浏览器缓存以及缓存的有效时间等。
Cache-Control可以出现在request header中,也可以出现在response header中,它有以下几个属性,这些属性决定了客户端和服务端交互时所采取的缓存策略。
max-age:(单位为s)指定设置缓存最大的有效时间,定义的是时间长短。
no-cache: 指定不缓存响应,表明资源不进行缓存,但是设置了 no-cache 之后并不代表浏览器不缓存,而是在获取缓存前要向服务器确认资源是否被更改。
no-store: 绝对禁止缓存。
s-maxage:(单位为s)同max-age,只用于共享缓存(比如CDN缓存)。
public: 指定响应会被缓存,并且在多用户间共享。
private: 响应只作为私有的缓存(见下图),不能在用户间共享。如果要求HTTP认证,响应会自动设置为 private。
Expires 是 HTTP 1.0 的字段,而 Cache-Control 是 HTTP 1.1 的字段,当 Expires 与 Cache-Control 同时存在时,Cache-Control 的优先级要高于 Expires。
若是命中缓存(即存在缓存资源并且缓存资源未过期),则浏览器响应 HTTP Status Code 200,并直接使用缓存资源作为返回结果,不需要发起 HTTP 请求;若是存在缓存资源但缓存资源已过期,则进入协商缓存。
2、协商缓存
Last-modified & If-modified-since
Last-Modified 是服务器端在响应请求时用来说明资源的最后修改时间。与之对应的是If-Modified-Since字段,在协商缓存过程中,浏览器发送的 HTTP 请求中 Header 中会带上 If-Modified-Since 字段,值为缓存资源 Last-Modified 属性的值。
当服务器端接收到带有 If-Modified-Since 的请求时,则会将 If-Modified-Since 的值与被请求资源的最后修改时间做对比。如果相同,说明资源没有新的修改,则响应 HTTP Status Code 304,浏览器会继续使用缓存资源;如果最后修改时间比较新,则说明资源被修改过,则响应 HTTP Status Code 200,并返回最新的资源。
Etag & & If-None-Match
Etag 是服务器端在响应请求时用来说明资源在服务器端的唯一标识。与之对应的是If-None-Match字段,在协商缓存过程中,浏览器发送的 HTTP 请求中 Header 中会带上 If-None-Match 字段,值为该缓存资源 Etag 属性的值。
当服务器端接收到带有 If-None-Match 的请求时,则会将 If-None-Match 的值与被请求资源的唯一标识做对比。如果相同,说明资源没有新的修改,则响应 HTTP Status Code 304,浏览器会继续使用缓存资源;如果不同,则说明资源被修改过,则响应 HTTP Status Code 200,并返回最新的资源。
Last-Modified 是 HTTP 1.0 的字段,而 Etag 是 HTTP 1.1 的字段,当 Last-Modified 与 Etag 同时存在时,Etag 的优先级要高于 Last-Modified。
Etag 的出现主要是为了解决 Last-Modified 存在的问题:
Last-Modified 标注的最后修改只能精确到秒级,如果某些文件在 1 秒钟以内被修改多次的话,它将不能准确标注文件的最后修改时间;
如果本地打开缓存文件,即使没有对文件进行修改,但 Last-Modified 却改变了,导致文件没法使用缓存;
参考文章: