描述
同一个标签页,打开 A 站点,访问 config 接口,正常;打开 B 站点,访问 config 接口,正常;通过浏览器后退返回 A 站点,访问 config 接口,数据异常,config 返回了 B 站点的数据。
测试站点数据
https://a.aaa.com
https://b.bbb.com
分析
判断是否是前端问题
通过观察,后退时仍然向服务器发送了请求,调用了 config 接口,可以排除
判断是不是前端本地存储未更新
通过观察,config 接口返回的内容仍然是 B 站点的数据,排除本地存储未更新
结论:后端返回数据未更新
(好了,锅甩出去了)
but,站点已经改变了,接口也重新请求了,为什么后端返回数据未更新
结论:浏览器缓存问题
原理:符合缓存策略时,服务器不会发送新的资源,但不是说客户端和服务器就没有会话了,客户端还是会发请求到服务器的,响应的是缓存的内容。
如何解决
后端:在响应头中添加 cache-control: no-store
前端:在 ajax 请求 url 后面加上一个随机数
原理:ajax 填入相同的 url 的时候会使用缓存
常用的修改随机数的方法
url=xxxxxxxx?time=new Date(); // 加时间戳
url=xxxxxxxx?number=Math.random(); // 加随机数
对比解决方案
为什么不能设置请求头 Cache-Control: no-cache?
catch-control 是客户端单向的指令,服务器端可能没有同样的指令
为什么不能设置 meta 标签?
<html>
<meta http-equiv="pragma" content="no-cache" />
<meta http-equiv="Cache-Control" content="no-store, must-revalidate" />
<meta http-equiv="expires" content="Wed, 26 Feb 1997 08:21:57 GMT" />
<meta http-equiv="expires" content="0" />
</html>
meta 标签的解析实现不是所有浏览器的必然支持的,你给了某个标签,也只是建议浏览器应该怎么做而已,具体的浏览器对页面缓存的设置可能会让表现有异常
memory cache 内存缓存就是这样的,从这里获取内容时,就是会忽略些头部配置,比如 no-cache 或者 max-age=0 之类的。
如果想确保一定是新的,就要在服务端响应头中设置 cache-control:no-store
终于解决了 bug,现在可以来看一看 Cache-Control 是一个什么东西了。
Cache-Control
用于 HTTP 请求和响应中的,通过指定指令实现缓存机制。缓存指令是单向的,意味着在请求中设置的指令,不一定被包含在响应中。
指令(参数)
public
响应可以被任何对象(客户端、代理服务器等)缓存
no-cache
强制要求缓存把请求提交给原始服务器进行验证(协商缓存验证)
no-store
不使用任何缓存
max-age
缓存最大周期
must-revalidate
一旦资源过期,在成功向原始服务器验证之前,不能缓存响应后的任何数据
缓存控制
控制是否开启缓存
字段:Pragma 和 Cache-Control
Pragma:no-cache 禁用缓存 (HTTP/1.0)
Cache-Control:缓存控制 (HTTP/1.1)
注意:符合缓存策略时,服务器不会发送新的资源,但不是说客户端和服务器就没有会话了,客户端还是会发请求到服务器的。
优先级从高到低是 Pragma -> Cache-Control -> Expires
缓存校验
校验缓存是否过期
字段:Expires 和 Last-Modified 和 etag
Expires:缓存有效时间 (HTTP/1.0)
Last-Modified:资源最后修改时间 (HTTP/1.1)
etag:用于处理修改时间变了,但是内容没变的 bug (HTTP/1.1)