参考资料
彻底解决让用户清一下浏览器缓存
浏览器缓存
彻底理解浏览器的缓存机制
彻底弄懂前端缓存
浅解强缓存和协商缓存
浏览器缓存策略(强缓存和协商缓存)
一文搞定Http缓存-强制缓存与协商缓存
前端浏览器缓存知识梳理
ASP.NET Core 中使用缓存
IIS中设置Cache-Control
是什么
当我们第一次访问网站的时候,比如 baidu.com ,电脑会把网站上的图片和数据下载到电脑上,当我们再次访问该网站的时候,网站就会从电脑中直接加载出来,这就是缓存。
优点:
减少了冗余的数据传输,节省网费;
提升性能,加快了客户端加载网页的速度;
减少服务器的负担,提升网站性能;
缺点:
如果处理不当,可能会导致服务端代码更新了,但是用户却还是老页面;
消耗内存或者存储;
Web缓存种类: 数据库缓存,CDN缓存,代理服务器缓存,浏览器缓存。
浏览器缓存:浏览器将用户请求过的静态资源(html、css、js),存储到电脑本地,当浏览器再次访问时,就可以直接从本地加载了,不需要再去服务端请求了。
浏览器缓存 是由服务端设置的!!!
缓存命中显示
从服务器获取新的资源
命中强缓存,且资源没过期,直接读取本地缓存
命中协商缓存,且资源未更改,读取本地缓存
注意:协商缓存无论如何,都要向服务端发请求的,只不过,资源未更改时,返回的只是header信息,所以size很小;而资源有更改时,还要返回body数据,所以size会大。
缓存流程
缓存规则
强缓存
简单粗暴,如果资源没过期,就取缓存,如果过期了,则请求服务器。
主要是看Response Headers中的 Cache-Control ,图中的max-age = 25xxx,就是说在这些秒内,都直接使用缓存,超过了就继续请求服务器。
Expires:Expires是HTTP/1.0的字段,和 Cache-Control 并列的,现在现在浏览器默认使用的是HTTP/1.1,所以不用管。
Cache-Control 服务端参数:
private:仅浏览器可以缓存,Cache-Control的默认取值
public:浏览器和代理服务器都可以缓存(对于private和public,前端可以认为一样,不用深究)
max-age=xxx:过期时间(重要)
s-maxage: 就是用于表示 cache 服务器上(比如 cache CDN,缓存代理服务器)的缓存的有效时间的,并只对 public 缓存有效。
no-cache:不进行强缓存(重要)
no-store:不强缓存,也不协商缓存
注意:规则可以同时多个
Cache-Control 客户端参数:
max-stale: 5 表示客户端到代理服务器上拿缓存的时候,即使代理缓存过期了也不要紧,只要过期时间在 5 秒之内,还是可以从代理中获取的。
min-fresh: 5 表示代理缓存需要一定的新鲜度,不要等到缓存刚好到期再拿,一定要在到期前 5 秒之前的时间拿,否则拿不到。
only-if-cached 这个字段加上后表示客户端只会接受代理缓存,而不会接受源服务器的响应。如果代理缓存无效,则直接返回 504(Gateway Timeout)。
强缓存流程:
协商缓存
协商缓存就是强缓存失效后,浏览器携带缓存标识向服务器发送请求,由服务器根据缓存标识来决定是否使用缓存的过程。
触发条件:
Cache-Control 的值为 no-cache (不强缓存)
或者 max-age 过期了 (强缓存,但过期了)
协商缓存的相关规则:
ETag:每个文件有一个,改动文件了就变了,可以看似md5
Last-Modified:文件的修改时间
协商缓存过程:每次http返回来Response Headers 中的 ETag和 Last-Modified,在下次请求时在Request Headers就把这两个带上(但是名字变了ETag–>If-None-Match,Last-Modified–>If-Modified-Since ),服务端把你带过来的标识,资源目前的标识,进行对比,然后判断资源是否更改了。
第1次请求:
第n次请求:
协商缓存流程:
请求资源时,把用户本地该资源的 ETag 同时带到服务端,服务端和最新资源做对比。
如果资源没更改,返回304,浏览器读取本地缓存。
如果资源有更改,返回200,返回最新的资源。
为什么要有Etag
你可能会觉得使用Last-Modified已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要Etag呢?HTTP1.1中Etag的出现(也就是说,ETag是新增的,为了解决之前只有If-Modified的缺点)主要是为了解决几个Last-Modified比较难解决的问题:
一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;
某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒);
某些服务器不能精确的得到文件的最后修改时间。
强缓存与协商缓存的区别
缓存存储位置
按缓存位置分类我们可以分为memory cache、disk cache、Service Worker三类,我们可以在 Chrome 的开发者工具中,Network -> Size 一列看到一个请求最终的处理方式:如果是大小 (多少 K, 多少 M 等) 就表示是网络请求,否则会列出 from memory cache、from disk cache、from ServiceWorker就表示命中了缓存。
查找浏览器缓存时会按顺序查找: Service Worker–>Memory Cache–>Disk Cache–>Push Cache。
Service Worker:是运行在浏览器背后的独立线程,一般可以用来实现缓存功能。使用 Service Worker的话,传输协议必须为 HTTPS。因为 Service Worker 中涉及到请求拦截,所以必须使用 HTTPS 协议来保障安全。Service Worker 的缓存与浏览器其他内建的缓存机制不同,它可以让我们自由控制缓存哪些文件、如何匹配缓存、如何读取缓存,并且缓存是持续性的。
Memory Cache:内存中的缓存,主要包含的是当前中页面中已经抓取到的资源,例如页面上已经下载的样式、脚本、图片等。读取内存中的数据肯定比磁盘快,内存缓存虽然读取高效,可是缓存持续性很短,会随着进程的释放而释放。一旦我们关闭 Tab 页面,内存中的缓存也就被释放了。
Disk Cache:存储在硬盘中的缓存,读取速度慢点,但是什么都能存储到磁盘中,比之 Memory Cache 胜在容量和存储时效性上。
Push Cache:Push Cache(推送缓存)是 HTTP/2 中的内容,当以上三种缓存都没有命中时,它才会被使用。它只在会话(Session)中存在,一旦会话结束就被释放,并且缓存时间也很短暂,在Chrome浏览器中只有5分钟左右,同时它也并非严格执行HTTP头中的缓存指令。
缓存配置
nginx:
add_header Cache-Control "no-cache";
location / {
# 其它配置
...
if ($request_uri ~* .*[.](js|css|map|jpg|png|svg|ico)$) {
#非html缓存1个月
add_header Cache-Control "public, max-age=2592000";
}
if ($request_filename ~* ^.*[.](html|htm)$) {
#html文件使用协商缓存
add_header Cache-Control "no-cache";
}
}
vue 项目:
脚手架已经将更改的文件做 hash 处理了,因此一般的 js、css 文件不需要我们再去操作。
而对于 index.html,我们需要在 nginx 上做 no-cache 处理,即完全不缓存 index.html,每次都请求最新的html,因为 html 中会外链 css、js,如果 html 还是走的缓存,那链接的还是老的 css。
IIS:
<configuration><system.webServer><staticContent><clientCache cacheControlCustom="public" cacheControlMode="UseMaxAge" cacheControlMaxAge="300.00:00:00" /></staticContent><caching><profiles><add extension=".css" policy="DontCache" kernelCachePolicy="CacheUntilChange" duration="30:00:30" /><add extension=".js" policy="DontCache" kernelCachePolicy="CacheUntilChange" duration="30:00:30" /></profiles></caching></system.webServer></configuration>
java:
.net core:
ResponseCache可以放到方法上,也可以标注到 Class 上。
[HttpGet]
[ResponseCache(Duration = 10)]
public DateTime GetNow()
{
return DateTime.Now;
}
用户行为对缓存的影响
缓存失效方案
手动修改:
老方案通过人工自己修改文件名或者在文件名后带上版本号、时间戳,这样客户端就会当新文件请求并使用,之前的强缓存就算在有效期内也会失效。
自动构建:hash值来给文件命名
在现在的构建阶段基本上都不需要人工操作了,都是使用构建工具比如Wbpack、Gulp、Grunt等构建工具自动构建。比如在使用Webpack构建的时候,会根据文件名或文件内容自动计算hash值来给文件命名,当内容或文件名发生改变的时候,构建出来的文件名也一定会不一样,这样也解决了强缓存还在有效期内的问题。
清除客户端全部缓存:Ctrl+Shift+Delete
单独清除某个缓存,如下图:
设置不缓存