http 缓存那些事

253 阅读4分钟

简介

http 的缓存都是从资源的第二次请求开始的,因为首次请求都是新的资源。

浏览器 http 缓存可以分为强缓存协商缓存

强缓存和协商缓存的区别是:

  • 命中强缓存,请求不会发送到服务器,此时 http 状态码为200
  • 如果没有命中强缓存,则发送请求到服务器,若命中协商缓存,则返回304状态码

下表所列缓存按照优先级进行排序:

字段名称 字段分类
Pragma 请求头&响应头
Cache-Control 请求头&响应头
Expires 响应头
If-None-Match / ETag 请求头 / 响应头
If-Modified-Since / Last-Modified 请求头 / 响应头

强缓存

强缓存在未失效的情况下(即 Cache-Control 的值没有过期或者 Expires 的缓存时间没有过期),那么就会直接使用浏览器的缓存数据,不会再向服务器发送任何请求。强制缓存生效时,http 状态码为 200。

Pragma

Pragma 是一个在 HTTP/1.0 中规定的通用首部,它在响应头的行为没有规范,依赖于浏览器的实现,建议只在需要兼容 HTTP/1.0 客户端的场合下应用。参数只有一个:no-cache,会通知浏览器不直接使用强缓存,因为它优先级最高,当存在时一定不会命中强缓存。

Cache-Control

Cache-Control 也是 HTTP/1.1 控制浏览器缓存的主流字段,被用于在请求和响应中。请求头和相应头指令略有不同,这里列举几个常见的指令:

  • max-age=<s>:设置缓存存储的最大周期,超过这个时间缓存被认为过期(单位秒)。
  • s-maxage=<s>:会覆盖max-age或者Expires头,但是仅适用于共享缓存
  • public:响应头专有,表明响应可以被任何对象(包括:发送请求的客户端,代理服务器,等等)缓存
  • private:响应头专有,表明响应只能被单个用户缓存,不能作为共享缓存(即代理服务器不能缓存它)
  • no-cache:不触发强缓存,此时会触发协商缓存
  • no-store:不使用缓存,此时也不会触发协商缓存

Expires

Expires 是一个响应首部字段,它指定了一个日期/时间(值为GMT时间,即格林尼治时间),在这个时间/日期之前,缓存被认为是有效的。如果在 Cache-Control 响应头设置了 "max-age" 或者 "s-max-age" 指令,那么 Expires 头会被忽略。

协商缓存

当 Cache-Control 和 Expires 过期或者 Cache-Control 的属性设置为 no-cache 时,那么此时浏览器就会发送请求与服务器进行协商,服务器端对比判断资源是否进行了修改更新。如果资源没有修改,那么就会返回 304 状态码,告诉浏览器可以使用缓存中的数据,减少服务器的数据传输压力。

If-None-Match / ETag

ETag 是一个响应首部字段,它是根据实体内容生成的一段hash字符串,标识资源的状态,由服务端产生。If-None-Match 是相应的请求头字段。当与 If-Modified-Since 一同使用的时候,If-None-Match 优先级更高

If-Modified-Since / Last-Modified

Last-Modified 是一个响应首部字段,包含该资源上次修改的时间。 If-Modified-Since 是相应的请求头字段。

协商缓存流程:

当浏览器第一次向服务器发送请求时,会在响应头中返回协商缓存的属性:ETag 和 Last-Modified,然后浏览器在第二次发送请求的时候,会在请求头中带上与 ETag 对应的 If-Not-Match,其值就是响应头中返回的 ETag 的值,Last-Modified 对应的 If-Modified-Since。服务器在接收到这两个参数后会做比较,如果返回的是304状态码,则说明请求的资源没有修改,浏览器可以直接在缓存中取数据,否则,服务器会直接返回数据。

from memory cache与from disk cache

当浏览器触发强缓存时,我们会看到资源会显示 from memory cache 或者 from disk cache 的字样,正常情况下,当我们这在访问页面时,资源会从内存中加载,即 from memory cache,如果我们关闭浏览器,然后从新打开页面,就会从磁盘加载该文件(前提是都触发了强缓存),即 from disk cache,当我们再次刷新是,资源又会被放到内存里了。