HTTP浏览器缓存知识回顾

90 阅读4分钟

知识点速览:

  • 什么是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

MDN文档

是服务器端生成的有效时间,遵循 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-ModifiedEtag 在缓存策略中如何使用,文章给的流程图很清晰了。

第一次请求:

image.png

第二次请求:

image.png

Vary

区分响应的方式本质上是基于它们的 URL。当浏览器发起相同的 url 请求时,才会做判断并决定是否走缓存策略。

但响应内容不止取决于url,可能还与其他请求表头的值有关,如Accept、Accept-LanguageAccept-Encoding

Vary 给我们提供了更细粒度的判断方式:当请求相同url,但是请求头 Accept-Language 不同时,不走缓存。

Vary: Accept-Language

一般应用于代理服务器缓存,此文有详细例子

浏览器端

客户端判断缓存,只能通过 Expires 或者 max-age 做时间维度上的判断。

通过设置请求头字段(如 Cache-Control ),也可以影响发请求的缓存策略。

设置方式:

  • 用户操作。比如 chrome 浏览器刷新 ctrl + shift + r,会设置 Cache-Control: no-cache。
  • 代码设置。代码也可以设置请求头参数,参考上一小节响应头字段即可,不细说了。

无法被浏览器缓存的情况

  1. HTTP 信息头中包含 Cache-Control:no-cache,pragma:no-cache(HTTP1.0),或 Cache-Control:max-age=0 等告诉浏览器不用缓存的请求
  2. 需要根据 Cookie,认证信息等决定输入内容的动态请求是不能被缓存的
  3. 经过 HTTPS 安全加密的请求(有人也经过测试发现,ie 其实在头部加入 Cache-Control:max-age 信息,firefox 在头部加入 Cache-Control:Public 之后,能够对 HTTPS 的资源进行缓存,参考《HTTPS 的七个误解》)
  4. POST 请求无法被缓存
  5. HTTP 响应头中不包含 Last-Modified/Etag,也不包含 Cache-Control/Expires 的请求无法被缓存