答案
如果 HTML 标签(比如script或link等)上设置了crossorigin="anonymous"的话,跟没有设置该属性的请求是不会共用连接的。
问题
前几天打开线上网站发现等得时间非常久,于是打开控制台刷新了下,有个脚本居然花了 50 多秒才下载下来:
是可忍,孰不可忍?
排查
从图上可以看到,大部分时间都花在 stalled
阶段,看官方的解释,说停留在 stalled
阶段的原因与排队阶段是一样的,而排队阶段可能由于下列原因造成阻塞:
- 有更高优先级的请求
- 已经打开了 6 个 TCP 连接,这是 HTTP/1.0 和 HTTP/1.1 协议的限制
- 浏览器正在磁盘缓存中分配空间
第一点显然不成立,看图上那一段时间只有这一个请求。至于第二点,我这个站点是 https 协议,静态资源都在 CDN,已经是 http2 了,也不成立。第三点也不太合理,为什么这个请求要花这么久去分配空间呢?在上面那张图上,那个请求前面的 3 个 js 文件和 2 个 css 文件都是同一个 CDN,其他请求都没这么久的,就这个特别久。而且清除浏览器连接缓存后刷新页面,还有一定概率能重现。不过有可能不是阻塞在 stalled
阶段,也可能是 TCP 连接阶段:
一分多钟才建立连接,这网站还能用?
后面又试了几次,有 2 次甚至直接白屏了,控制台报了个超时的错误,是 webpack 打包后的代码里抛出来的(该 js 文件是前面一个 js 文件动态插入文档的):
这种情况网络面板是不会展示请求阶段耗时的,只有一个 stalled
的阶段,也不知道是哪里出了问题。
然后我突然想到,CDN 明明都是 https 协议,按道理应该多路复用,只需要一条 TCP 连接才对,为什么会出现重新建立连接的情况?
然后设置展示 connection ID
那一列,又多次刷新,发现每次都是这一个资源与别的资源的 ID 不一样。于是开始猜这个猜那个,比如请求数限制、延时请求、响应头字段之类的,也没看出来什么东西。
然后看了下公司官网,也有这种同个站点多条连接的情况。又看了下其他知名站点,比如腾讯网、新浪网之类的,多数真的是一条连接用到底,这种情况还挺难找的。
最后终于发现,如果 HTML 标签(比如script
或link
等)上设置了crossorigin="anonymous"
的话,跟没有设置该属性的请求是不会共用连接的。
然后重点就是研究这个 crossorigin 属性了,坦白说,还没搞懂。只知道不设置该属性、值设为use-credentials
都是一样的效果,会复用连接,只有anonymous
是特例。甚至 clone 了 chromium 的源码下来,想一探究竟,最终还是不得不向现实低头:这种事情不是我能把握的……
回到开头的问题,观察到线上 webpack 打包出的 html 文件的script
标签都是带了这个属性的,但是上面那个动态插入的 js 是没有的。这下就容易了,去 webpack 官方文档一搜就出来了:
不过还是不明白, 为什么当时测试的时候到了这个 js 建立连接的时候有一定概率会等很久,前面的都很快,难道是我刷新次数不够多?
也不知道是不是还有其他情况,会建立多条 TCP 连接的……