记一次线上故障根因排查

219 阅读3分钟

背景

大的公司一般都会有这样几个环境:开发环境、测试环境、预发布环境、生产环境,缺一不可;

  1. 开发环境缺失的话,测试和开发共用一个环境,那么开发联调过程中的频繁发布会影响到测试流程
  2. 预发布环境则相当于线上环境的测试,与线上环境数据类似,预发环境缺失的话会导致测试环境未排查出来的bug发布到线上 但是实际情况是:开发环境和预发环境可能都没有,心里祈祷不要出现bug,但是最终还是出现了;

那天我们测试环境通过之后就直接发布到生产环境了,然后我在生产环境验证了,本次发布没有问题;但是不一会儿测试就过来了,说他们那边有问题,请求一直失败;因为那个接口需要一个cookie,但是请求没有带上;后来我一看,我这边看都带上了啊,于是心里想:这肯定是他们那边环境的问题,我这次发布肯定没有问题,抱着这样的心态我依次让他们清缓存、重启浏览器、换safari、edge甚至重启电脑,但是都无济于事;下面我还原一下故障现场让大家思考一下到底是什么原因;

事故现场

需要准备的:switchhost、vscode LiveServer插件

第一步:首先我们用switch定义多个域名,他们分别为根域名、子域名:

127.0.0.1 test-love.com
127.0.0.1 me.test-love.com
127.0.0.1 you.me.test-love.com

第二步:html中填充问题代码,用LiveServer跑一个服务然后访问//me.test-love.com:5500/test.html

(async function () {
  const fetchRoot  = fetch('//test-love.com:5500/test.html')
  const fetchSub = fetch('//you.me.test-love.com:5500/test.html')
  const [root,sub] =await Promise.all([
      fetchRoot,
      fetchSub
  ])
  // ...
})()

我们主要观察一下请求头: 第一个请求://me.test-love.com:5500/test.html

image.png

第二个请求:fetch请求//test-love.com:5500/test.html

image.png

第三个请求:fetch请求//you.me.test-love.com:5500/test.html

image.png

fetch请求里面所有的cookie都没有携带,包括资源请求:img和script,这是为什么呢?

首先根域名和子域名之间的请求算不算跨域?应该是算跨域的,但是他们之间是可以请求的,因为服务器默认开启了CORS:

image.png

我们看一下此时的cookie:

image.png

这个cookie在根域名下,应该是所有子域名都适用的,所以问题还是出在请求的地方,是请求的方法没有携带cookie

我们来看一下fetch的官方描述:

为了让浏览器发送包含凭据的请求(即使是跨域源),要将 credentials: 'include' 添加到传递给 fetch() 方法的 init 对象。

要改为确保浏览器不在请求中包含凭据,请使用 credentials: 'omit'

如果你只想在请求 URL 与调用脚本位于同一起源处时发送凭据,请添加 credentials: 'same-origin',而默认值就是它

所以说问题终于找到了,那就是fetch发送CORS请求默认是不携带cookie的,扩展到axios等请求库上,它们对于CORS请求也都是默认不携带cookie的,只有同域请求才会携带cookie

总结

费了九牛二虎之力找到了问题的根源,发现它的根源就是这么的简单,这也提醒我应该多多地巩固基础知识,不在这种基础问题上犯迷糊