关于api请求被缓存从而引发的一连串知识(from disk cache)
起因
我写了一个axios的get请求,他会在网页加载后运行,从服务器获取数据,根据status状态值来判断我是否需要进行弹窗提示,弹窗会有一个按钮,点击后会通过location.href
跳转到另一个页面,在另一个页面,会有一个返回按钮,触发history.back()
返回上一页。
当然,在运行href跳转前,会通过api请求告诉后端,我已经点击了弹窗,下次请求不要再运行弹窗了。
但是在下一个页面点击返回时,弹窗依旧会被弹出,后端说他没有看到请求记录,但是前端f12依旧可以看到api请求,并返回了200状态码。
由于是手机调试,看不到具体的原因,只有在pc端,在不勾选停用缓存时,才能看到在请求的size上,会有from disk cache字样。
所以,很明显,api请求被缓存了。
为什么会被缓存
这就涉及到浏览器的缓存机制了,在浏览器的设计中,缓存是一个很重要的功能,基本上所有的东西都是优先缓存的,缓存既能减少服务器压力,也能加快本地的浏览速度。
当然缓存也是分区域的,有的是缓存在内存中,有的是缓存在磁盘中,这个具体的位置,我们不需要怎么了解,我们需要知道缓存的机制。
有两种缓存方式:
- 强缓存(也称本地缓存)
- 协商缓存
什么是强缓存
一般是在响应头信息上存在Cache-Control
或者Expires
的头信息,并且不是禁止缓存的属性,或者没有设置缓存头信息,浏览器都会将一些http的请求做强缓存,常见的就是get请求了,浏览器获取到的网页,js,css等文件。
在不设置缓存的头信息的情况下,并不意味着浏览器就不缓存了,他是有默认行为的:
如果什么缓存策略都没设置,浏览器会采用一个启发式的算法,通常会取响应头中的 Date 减去 Last-Modified 值的 10% 作为缓存时间。
If the response has a Last-Modified header field (Section 2.2 of [RFC7232]), caches are encouraged to use a heuristic expiration value that is no more than some fraction of the interval since that time.A typical setting of this fraction might be 10%.
不同浏览器可能会有不一样的方案,但是它确实会缓存。
什么是协议缓存
协议缓存的存在自然是因为强缓存存在缺陷,引用掘金里的一条评论:
因为强缓存有缺点呀,比如说,设置了expires,GMT格式,但是浏览器的时间可以改变,因此就通过cache-control返回一个相对时间来。但是假如说资源并没有更新,但是强缓存时间过期了,那就需要重新拉去资源,因此就有了last-modified,但是last-modified的时间单位是s,当1s内有资源修改,那浏览器返回的最后修改时间和上次的修改时间相同,那就不会重新拉取资源,因此推出了etag,通过比对资源内容来判断是否修改
协议缓存是通过Etag
头信息来进行文件比对,如果服务器端的Etag和浏览器端的Etag相同,那么就返回304,当然这其实也发送了请求,只是因为不返回内容,更快了而已。
Etag常常与Expires
、Last-Modified
配合使用,Expires规定缓存的过期时间,但是用户本地时间是可以被篡改的,服务器时间也可能不同步,所以增加了Last-Modified,Last-Modified表示资源的最后修改时间,这样客户端下次请求时,携带这些信息。服务器就会进行比对,如果修改时间不同,说明资源被修改,发送新的资源。反之则返回304
协商常用于比如js文件啊,图片文件啊,css啊,利用协议的特性,就可以做到资源即时更新,不用清理缓存。
问题的原因
很明显就是get请求被强缓存了,因为没有设置缓存头信息,会根据浏览器默认的行为进行处理,从而导致from disk cache
浏览器的history.back()
返回上一页,返回后页面会进行刷新,但是普通刷新是会使用缓存的。所以,导致这么个情况。
不缓存的解决办法
- 给get请求增加一个不重复字符串,比如时间戳:
http://xxxx.xxx/?time=2131231231
后端设置响应头信息,Cache-Control
设置为no-cache,private
,单单设置no-cache并不代表浏览器不缓存,而是在获取缓存前要向服务器确认资源是否被更改,因此需要加上private指令。- 前端请求头加上2里面的头信息,浏览器也会视为不缓存(没有具体测试)
2022-03-09 补充
经过个人测试,只有get请求会被强缓存,触发from disk cache
;解决办法中,头信息设置Cache-Control:no-cache
或者Cache-Control:no-cache,private
都是无效的,依旧会进行缓存。
只有设置Cache-Control:no-store
才不会被触发缓存,所以,建议是针对get请求做这个处理
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿站点。未经许可,禁止转载。
暂无评论数据