最近项目遇到一个问题,发版之后,用户需要清除缓存才可以访问到最新的应用,但是我们访问却可以正常。经过1天的研究搞懂了浏览器缓存的机制,记录下分析轨迹。
浏览器缓存基础知识
浏览器强缓存和协议缓存都是用来提高网页加载速度和减少网络传输的技朧。
强缓存
浏览器强缓存是通过设置HTTP响应头中的Cache-Control和Expires字段来指定浏览器在一定时间内直接从本地缓存中获取资源,而不会向服务器发送请求。这样可以减少网络传输时间,加快页面加载速度。常用的设置有max-age和s-maxage,分别表示资源的缓存时间。
命中强缓存条件
- Cache-Control: max-age=xxx
- 响应头有
Expires
- 响应头存在
ETag
和Last-Modified
(协商缓存)且 不存在Cache-Control:no-cache
强缓存非常有必要设置过期时间,如果没有设置过期时间,新系统升级之后浏览器内有强缓存,默认是走强缓存的。
协议缓存
协议缓存是通过使用ETag和Last-Modified字段来实现的。服务器在返回资源时会生成一个唯一的ETag标识和最后修改时间,浏览器在下次请求资源时会将这些信息发送给服务器,服务器根据这些信息判断资源是否发生变化,如果没有变化则返回304 Not Modified状态码,告诉浏览器直接从缓存中获取资源。这样可以减少网络传输和服务器负载。
协议缓存过程:
- 第一次请求服务器,服务器返回200状态码、Last-Modified时间戳、ETag签名和完整资源
- 浏览器保存资源内容,以及Last-Modified和ETag值
- 再次请求浏览器带上If-Modified-Since(值为上次服务器返回的Last-Modified)和If-None-Match(上次服务器返回的ETag)请求头
- 服务器收到请求后,对比当前资源文件的最后修改时间 是否等于 If-Modified-Since 以及资源文件的ETag 是否等于 If-None-Match (ETag优先级高于Last-Modified)
- 如果相同则返回304,客户端使用缓存
- 如果不相同则服务器返回资源,且返回新的ETag 和 Last-Modified,并更新到缓存
浏览器缓存流程
对于同一个url资源,不管服务器有没有更新资源,只要浏览器缓存时效未过期,都不会主动向服务器重新请求的
问题
系统升级之后,一部分用户反馈访问的还是旧系统,清除缓存之后才能访问新系统。
清除缓存这个问题对于开发来说是一个常规操作,甚至用户也成了默认行为,一直也没有彻底研究过,领导要求解决,趁这个机会研究下浏览器缓存机制。
f12 对界面进行了跟踪,定位到用户行为:
- 输入网址
- 回车
- 网站index.html 没有到服务器,直接
form disk cache
分析问题
现在访问直接走了磁盘缓存,没有走服务器。下面看下目前的请求和返回头。
因为Cache-Control: max-age=0
所以触发了强缓存的命中条件,同时如果本地没有强缓存的时候,触发协议缓存。
表现如下:
- 用户如果有强缓存则不访问服务器 (旧的系统)
- 如果之前没有访问的,没有强缓存或者失效的。第一次访问服务器返回200和资源并记录ETag 和 Last-Modified,第二次会304 走协商缓存。
如何修改
系统更新,用户的强缓存没有过期,直接走了强缓存,导致没有访问服务器最新资源。
三种方式修改:
- 使用强缓存,给强缓存设置短暂的过期时间比如1分钟
- 不使用强缓存,使用协商缓存
- 不使用缓存
建议直接在服务器更改比如nginx 、tomcat 。 客户端优先级低会被服务器覆盖掉。
强缓存设置过期时间
设置强过期的缓存时间为60秒,第一次请求服务器,如果60s之内请求走强缓存不访问服务器,过了时间之后走协商缓存。
设置max-age=60s
nginx 配置:
不使用强缓存,使用协议缓存
设置Cache-Control no-cache 不使用强制缓存
nginx 配置:
不缓存,每次都刷新
nginx 配置:
总结
缓存策略浏览器设置还是比较合理的,主要是强缓存带来的速度是非常快的,这样就存在风险。遇到问题还是需要仔细的分析,而不是知道了固有手段当成了正常流程。