概述
浏览器请求资源时,并不是直接发起http请求,而是会先检查本地有没有该文件的缓存,如果本地有未过期缓存,那么就不用发起http请求了,直接使用本地缓存(强缓存),这样可以大大加快网页响应速度;如果本地有缓存但是过期了,那么浏览器需要向服务器发起一个http请求询问该文件有没有修改过,如果有修改过,服务器返回新的文件,如果没有修改过,服务器返回304状态码及空响应体,浏览器收到该响应后会继续使用本地缓存(协商缓存)
缓存的目的就是减少不必要的资源加载时间,加快网页响应速度,提升用户体验。
那么,在整个过程中,浏览器如何判断缓存是否过期?缓存的位置在哪里?服务器如何判断文件是否修改过?带着这些问题我们继续往下看
缓存的两个阶段:强缓存 和 协商缓存
强缓存
强缓存的过程 :当浏览器首次请求资源时,服务器会将缓存规则放在http响应头字段里和响应体一同返回给浏览器,控制强缓存的响应头字段是Expires
和Cache-Control
,浏览器收到后,会将响应结果和缓存标识存入浏览器缓存中,当下次再次请求该资源时,会先在缓存里查找,如果找到了并且未过期,则直接使用该缓存,不再发送http请求,此时network里的状态码是一个灰色的200。
Expires:HTTP1.0 的特性,标识该资源过期的时间点。它的值是标准时间格式,如 Wed, 22 Nov 2019 08:41:00 GMT。即在这个时间点之后,缓存的资源过期。
缺点:服务端和客户端时间不一致的话,就会有误差。
Cache-Control
是HTTP1.1 提出的特性,主要为了弥补Expires的缺陷,取值为:
max-age:xxx(number):有效时间xxx秒,是一个相对值
public:客户端和代理服务器都可以缓存
private:只有客户端可以缓存
no-cache:走协商缓存,与服务器确认文件是否修改
no-store:不缓存,请求最新资源
s-maxage:针对代理服务器的缓存时间
注意:为了兼容各版本http协议,通常两个头部同时设置,当同时存在时,Cache-Control比Expires优先级高。
缓存的位置
打开浏览器network tab的size列,可以看到缓存的位置:
from memory cache(内存缓存)
存在于当前进程中,容量小,读取速度快。
存活时间短,当浏览器标签页关闭时,进程结束,内存缓存也就不存在了
from disk cache(硬盘缓存)
存在于磁盘中,容量大,需要I/O读写操作,所以速度比内存缓存慢
不随进程的结束而销毁,存储时间长
注意⚠️:刚开始从硬盘中读取,读取之后将比较小的文件保存在内存中,所以当刷新页面,部分文件的缓存位置会变为from memory cache
协商缓存
协商缓存过程:
当强缓存时间过期了,才会进入协商缓存阶段,上面说到,首次请求时服务器会将缓存相关的头字段放入响应报文里,其中也包含协商缓存相关的头字段,如Last-Modified 和Etag, 当强缓存失效时,浏览器会携带协商缓存字段If-Modified-Since和 If-None-Match 向服务器发起请求,If-Modified-Since 的值就是服务器之前返回的Last-Modified 的值,If-None-Match 的值就是Etag的值, 服务器根据此头字段判断文件在上次请求后有没有修改过,如果没有修改过,返回状态码304,并且响应体为空加快传输速度,如果修改过,返回200状态码和新文件内容。
Last-Modified / If-Modified-Since
HTTP1.0 的特性,Last-Modified是服务器响应请求时,返回该资源文件在服务器最后被修改的时间。当强缓存失效,浏览器会携带If-Modified-Since向服务器发起请求,服务器收到该请求,则会根据If-Modified-Since的字段值与该资源在服务器的最后被修改时间做对比,若服务器的资源最后被修改时间大于If-Modified-Since的字段值,则重新返回资源,状态码为200;否则则返回304,代表资源无更新,可继续使用缓存文件。
缺陷:
- Last-Modified精度只有秒级,当在一秒内再次请求该资源,即使文件修改过,也会返回304,导致客户端使用了旧的缓存。
- 编辑了文件,但内容并没有更改,(比如加一个字然后又把它删了)这样也会造成缓存失效。
Etag / If-None-Match
HTTP1.1 的特性,Etag是服务器响应请求时,返回当前资源文件的一个唯一标识,它是根据实体内容生成的一段 hash 字符串,由服务端产生。每当文件有修改,hash都会重新生成,就会与之前的不一样,服务器由此判断文件被修改过。
当强缓存失效,浏览器会携带If-None-Match向服务器发起请求,服务器收到该请求,则会根据If-None-Match的字段值与该资源在服务器的Etag值做对比,一致则返回304,代表资源无更新,继续使用缓存文件;不一致则重新返回资源文件,状态码为200
注意⚠️:为了兼容各版本http协议,通常两种头部字段同时设置,当同时存在时,Etag / If-None-Match比Last-Modified / If-Modified-Since优先级高。
Etag 对比 Last-Modified
1.在精准度上,ETag优于Last-Modified
-
Last-Modified精度只有妙级
-
如果编辑了文件,但内容并没有更改,(比如加一个字然后又把它删了)Last-Modified也会改变
2.在性能上,Last-Modified优于ETag
- Last-Modified仅仅只是记录一个时间点,而 Etag需要根据文件的具体内容生成哈希值,需要使用哈希算法去计算,有一定的时间复杂度。
总结
用一个思维导图总结: