起因

我写了一个axios的get请求,他会在网页加载后运行,从服务器获取数据,根据status状态值来判断我是否需要进行弹窗提示,弹窗会有一个按钮,点击后会通过location.href跳转到另一个页面,在另一个页面,会有一个返回按钮,触发history.back()返回上一页。

当然,在运行href跳转前,会通过api请求告诉后端,我已经点击了弹窗,下次请求不要再运行弹窗了。

但是在下一个页面点击返回时,弹窗依旧会被弹出,后端说他没有看到请求记录,但是前端f12依旧可以看到api请求,并返回了200状态码。

由于是手机调试,看不到具体的原因,只有在pc端,在不勾选停用缓存时,才能看到在请求的size上,会有from disk cache字样。

所以,很明显,api请求被缓存了。

为什么会被缓存

这就涉及到浏览器的缓存机制了,在浏览器的设计中,缓存是一个很重要的功能,基本上所有的东西都是优先缓存的,缓存既能减少服务器压力,也能加快本地的浏览速度。

当然缓存也是分区域的,有的是缓存在内存中,有的是缓存在磁盘中,这个具体的位置,我们不需要怎么了解,我们需要知道缓存的机制。

有两种缓存方式:

  1. 强缓存(也称本地缓存)
  2. 协商缓存

什么是强缓存

一般是在响应头信息上存在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常常与ExpiresLast-Modified配合使用,Expires规定缓存的过期时间,但是用户本地时间是可以被篡改的,服务器时间也可能不同步,所以增加了Last-Modified,Last-Modified表示资源的最后修改时间,这样客户端下次请求时,携带这些信息。服务器就会进行比对,如果修改时间不同,说明资源被修改,发送新的资源。反之则返回304

协商常用于比如js文件啊,图片文件啊,css啊,利用协议的特性,就可以做到资源即时更新,不用清理缓存。

问题的原因

很明显就是get请求被强缓存了,因为没有设置缓存头信息,会根据浏览器默认的行为进行处理,从而导致from disk cache

浏览器的history.back()返回上一页,返回后页面会进行刷新,但是普通刷新是会使用缓存的。所以,导致这么个情况。

不缓存的解决办法

  1. 给get请求增加一个不重复字符串,比如时间戳:http://xxxx.xxx/?time=2131231231
  2. 后端设置响应头信息,Cache-Control设置为no-cache,private,单单设置no-cache并不代表浏览器不缓存,而是在获取缓存前要向服务器确认资源是否被更改,因此需要加上private指令。
  3. 前端请求头加上2里面的头信息,浏览器也会视为不缓存(没有具体测试)

2022-03-09 补充

经过个人测试,只有get请求会被强缓存,触发from disk cache;解决办法中,头信息设置Cache-Control:no-cache或者Cache-Control:no-cache,private都是无效的,依旧会进行缓存。

只有设置Cache-Control:no-store才不会被触发缓存,所以,建议是针对get请求做这个处理

分类: 教程 标签: http强缓存协商缓存apiCache-Controlno-cacheprivate

评论

暂无评论数据

暂无评论数据

目录