HTTP 的缓存机制
缓存分为两种:强缓存和协商缓存
强缓存
不会向服务器发送请求,直接从缓存中读取资源
Header
-
Expires: response header 里的过期时间,浏览器再次加载资源时,如果在这个过期时间里则命中强缓存
-
Cache-Control:当值设为 max-age=300 时,则代表这个请求正确返回时间的5分钟内再次加载资源,就会命中强缓存
区别:Expires 是 http1.0 的产物,Cache-Control 是 http 1.1 的产物,两者同时存在的话,Cache-Control 优先级高于 Expires
协商缓存
向服务器发送请求,服务器会根据这个请求的 request header 的一些参数来判断是否命中协商缓存,如果命中,则返回 304 状态码,并带上新的 request header 通知浏览器从缓存中读取资源
Header
-
ETag 和 If-None-Match:
ETag 是上一次加载资源时,服务器返回的 response header,是对资源的一种唯一标识,只要资源有变化,ETag 就会重新生成
浏览器在下一次加载资源向服务器发送请求时,会将上一次返回的 ETag 值放到 request header 的 If-None-Match 中,服务器将其与资源文件的 ETag 值做比较,如果相同,则表示资源文件没有发生改变,命中协商缓存,返回 304 状态码
-
Last-Modified 和 If-Modified-Since:
Last-Modified 是资源文件的最后一次更改时间,服务器会在 response header 里返回,同时浏览器会将这个值保存起来,在下一次请求时,放到 request header 里的 If-Modified-Since里
服务器在接受到后也会做对比,如果相同则命中缓存
在精确度上,Etag 要优于 Last-Modified ,Last-Modified 的时间单位是秒,如果某个文件在 1 秒内改变了多次,那么他们的 Last-Modified 其实并没有体现出来修改,但是 Etag 每次都会改变确保了精度
在性能上,Etag 要逊于 Last-Modified,毕竟其只是记录时间,而 Etag 需要服务器计算出响应的 hash 值
在优先级上,服务器校验优先考虑 Etag。
所以,两者互补
**共同点:**都是从客户端缓存中读取资源
**区别:**强缓存不会发请求,协商缓存会发请求
浏览器缓存过程
- 浏览器第一次加载资源,服务器返回200,浏览器将资源文件从服务器上请求下载下来,并把 response header 及该请求的返回时间一并缓存
- 下一次加载资源时,先比较当前时间和上一次返回200时的时间差,如果没有超过 Cache-Control 设置的 max-age,则没有过期,命中强缓存,不发请求直接从本地缓存读取该文件 (如果浏览器不支持 HTTP 1.1,则用 Expires 判断是否过期)
- 如果时间过期,服务器则查看 header 里的 If-None-Match (判断hash值)和 If-Modified-Since(判断最后一次修改时间)
- 服务器优先根据 Etag 的值判断请求的文件有没有做修改,Etag 一致则没有修改,命中协商缓存,返回 304,如果不一致则有改动,直接返回新的资源文件带上新的 Etag 值并返回 200
- 如果服务器收到请求没有 Etag 值,则将 If-Modified-Since 和被请求的最后修改时间做比对,一致则命中协商缓存,返回 304;不一致则返回新的 Last-Modified 和文件资源 并返回200
使用协商缓存主要是为了进一步降低数据传输量,如果数据没有变,就不必要再传一遍
(本文转载自 https://zhuanlan.zhihu.com/p/58685072)