http缓存分为强缓存
和协商缓存
。
● 每次发起请求,浏览器都会先在浏览器缓存中查找该请求的结果以及缓存标识。
● 每次拿到请求结果都会将结果和缓存标识存入浏览器缓存中。
强缓存
强缓存就是强制缓存,不需要发送请求到服务端,直接读取浏览器本地缓存。
在 Chrome 的 Network 中显示的 HTTP 状态码是 200 ,在 Chrome 中,强制缓存又分为 disk cache (存放在硬盘中)和 memory cache (存放在内存中),存放的位置是由浏览器控制的。
● 内存缓存(from memory cache):js和图片等文件解析执行后直接存入内存缓存中,那么当刷新页面时只需直接从内存缓存中读取。
● 硬盘缓存(from disk cache):硬盘缓存则是直接将缓存写入硬盘文件中,读取缓存需要对该缓存存放的硬盘文件进行I/O操作,然后重新解析该缓存内容,读取复杂,速度比内存缓存慢。
Cache-Control
HTTP/1.1 中新增的属性,在请求头和响应头中都可以使用。
常见属性值如有:
- max-age:用来设置资源可以缓存多长时间,单位s;
- public:指示响应可被任何缓存区缓存;
- private:只能针对个人用户,而不能被代理服务器缓存;
- no-cache:不使用强缓存,需要与服务器验证,评估缓存响应的有效性;
- no-store:禁止一切缓存(这个才是响应不被缓存的意思);
cache-control: public, max-age=3600
如上响应头,表示则该资源会被缓存(3600秒) 1 小时,在 1 小时内都会从缓存中获取资源直接使用。
Expires
响应头包含日期/时间(GMT时间), 即在此时间之后,响应过期。
expires: Wed, 21 Oct 2015 07:28:00 GMT
无效的日期,比如 0, 代表着过去的日期,即该资源已经过期。
注意:Expires响应头是一个绝对时间,而Cache-Control是相对时间。
协商缓存
协商缓存就是强缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程,主要有以下两种情况:
● 协商缓存生效,返回304 not modified
,告知浏览器缓存可用。
● 协商缓存失效,返回200
和数据(可能会更新强缓存,具体看服务器操作)。
控制协商缓存的字段分别有:Last-Modified
/ If-Modified-Since
和 Etag
/ If-None-Match
。其中Etag
/ If-None-Match
的优先级比Last-Modified
/If-Modified-Since
高。
注意:服务端返回的响应头中得包含Last-Modified
或者Etag
这两个响应头之一,下次浏览器请求该资源才会带上对应的请求头。
Last-Modified
Last-Modified
是服务器响应请求时,返回该资源文件在服务器最后被修改的时间。
第二次发起请求的时候,请求头会带上上一次响应头中的 Last-Modified
的时间,并放到If-Modified-Since
请求头中。服务端根据文件最后一次修改时间和If-Modified-Since
的值进行比较。
如果相等则返回 304 ,代表资源无更新,继续使用浏览器缓存文件。
如果服务器的资源最后被修改时间大于If-Modified-Since的字段值,则重新返回资源,状态码为200。
在Nodejs中,可以通过fs.statSync(path).mtime
获取文件的最后修改时间。
注意:Last-Modified是秒级别的,如果在这一秒内多次修改文件则Last-Modified
不会改变,浏览器下次请求就会认为资源没有发生变化,这也是为什么会有ETag的原因。
Etag
Etag
是服务器响应请求时,返回包含在响应头的当前资源文件的一个唯一标识(由服务端生成)。
If-None-Match
是客户端再次发起该请求时,携带上次请求返回的唯一标识Etag
值。
服务器收到请求后,则会根据If-None-Match
的值与该资源在服务器中计算出的Etag
值做比较。
如果相等则返回304,代表资源无更新,继续使用浏览器缓存文件。
如果不相等则重新返回资源文件,状态码为200。
优点
缓解服务器端压力,提升性能,优化用户体验。
缺点
强缓存需要设置绝对时间或者相对时间,由于我们无法判断具体多长时间资源会发生变化,就有可能导致资源更新后,该资源还处于缓存期间。
一个比较好的解决方案是:改变资源后给资源加上一个哈希路径,同时把引用该资源的路径改为变更后的路径,让浏览器主动放弃缓存,加载新资源。当然,如果用户没有刷新页面,还是会用旧的资源。