知识点速览:
- 什么是HTTP浏览器缓存,为什么需要HTTP浏览器缓存
- 如何设置缓存
- 无法被浏览器缓存的情况
什么是HTTP浏览器缓存,为什么需要HTTP浏览器缓存
HTTP 缓存( web 缓存),是用于临时存储Web文档(如HTML页面和图像)、减少服务器延迟的一种技术,存在于服务器和客户端。
web 开发常见的缓存类型分为:
- 服务器缓存
- 代理服务器缓存
- CDN 缓存
- 浏览器缓存
如何设置缓存
浏览器的 http 缓存策略,是由服务器和客户端共同控制的。
- 服务器端可以在响应头中添加Cache-Control等字段来告诉客户端是否可以存储响应。
- 客户端一般指浏览器,浏览器端可以通过在请求头里添加Cache-Control等字段来决定是否走缓存。
服务器端
启发式缓存
缺少 Cache-Control 字段,满足某些条件,响应也会被存储和重用的缓存方式。
正常应该指定 Cache-Control,特地记录此知识,只为排查 bug 作参考点。
// Date 和 Last-Modified 会启用重用,复用多长时间取决于浏览器实现
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1024
Date: Tue, 22 Feb 2022 22:22:22 GMT
Last-Modified: Tue, 22 Feb 2021 22:22:22 GMT
<!doctype html>
…
非启发式缓存
(参数配套对了的,就走非启发式缓存喽)
通过往响应头添加字段实现,接下来将依次介绍:
- Expires
- Cache-Control
- Last-Modified
- Etag
- Vary
Expires
是服务器端生成的有效时间,遵循 GMT 格式。是 http 1.0 产物,一般为了向下兼容设置。
浏览器发起请求时,如果时间超过有效期,则向服务器请求资源,否则走本地缓存 (200 from cache)。
失效情况:与 Cache-Control 设置冲突时,失效。
Cache-Control
- max-age:缓存有效时长,浏览器端会在 Date 的基础上判断是否缓存过期,即 max-age + Date > now。
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1024
Date: Tue, 22 Feb 2022 22:22:22 GMT
Last-Modified: Tue, 22 Feb 2021 22:22:22 GMT
<!doctype html>
…
- no-store:不允许缓存,但不会删除已存储的相同 url 的响应。
- no-cache:允许缓存,每次请求,都要向服务器确认资源是否过期。
- must-revalidate: 允许缓存,如果缓存时间过期,再去服务器端确认资源是否过期。
- private:只允许特定客户端缓存——通常是浏览器缓存。一般存储该用户的个性化响应,应该配合 no-store 使用。
Last-Modified
响应头字段,表示当前请求的资源的最后修改时间,如果响应头中有该字段,那么下次请求的时候,请求头中就会包含if-Modified-Since字段,值为这个 Last-Modified。服务器做对应资源比对,如果没有变化,则返回状态码304,否则返回200。
Etag
资源的唯一标识,那如果响应头中有该字段,则下次请求的时候,请求头中就会有If-None-Match字段,它的值就是ETag的值。服务器做对应资源比对,如果没有变化,则返回状态码 304,否则返回200。
关于 Last-Modified 和 Etag 在缓存策略中如何使用,文章给的流程图很清晰了。
第一次请求:
第二次请求:
Vary
区分响应的方式本质上是基于它们的 URL。当浏览器发起相同的 url 请求时,才会做判断并决定是否走缓存策略。
但响应内容不止取决于url,可能还与其他请求表头的值有关,如Accept、Accept-Language和Accept-Encoding。
Vary 给我们提供了更细粒度的判断方式:当请求相同url,但是请求头 Accept-Language 不同时,不走缓存。
Vary: Accept-Language
一般应用于代理服务器缓存,此文有详细例子。
浏览器端
客户端判断缓存,只能通过 Expires 或者 max-age 做时间维度上的判断。
通过设置请求头字段(如 Cache-Control ),也可以影响发请求的缓存策略。
设置方式:
- 用户操作。比如 chrome 浏览器刷新 ctrl + shift + r,会设置 Cache-Control: no-cache。
- 代码设置。代码也可以设置请求头参数,参考上一小节响应头字段即可,不细说了。
无法被浏览器缓存的情况
- HTTP 信息头中包含 Cache-Control:no-cache,pragma:no-cache(HTTP1.0),或 Cache-Control:max-age=0 等告诉浏览器不用缓存的请求
- 需要根据 Cookie,认证信息等决定输入内容的动态请求是不能被缓存的
- 经过 HTTPS 安全加密的请求(有人也经过测试发现,ie 其实在头部加入 Cache-Control:max-age 信息,firefox 在头部加入 Cache-Control:Public 之后,能够对 HTTPS 的资源进行缓存,参考《HTTPS 的七个误解》)
- POST 请求无法被缓存
- HTTP 响应头中不包含 Last-Modified/Etag,也不包含 Cache-Control/Expires 的请求无法被缓存