简介
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,当我们再次刷新是,资源又会被放到内存里了。