谷歌浏览器不支持HTTP2的多路复用。

9
我正在构建一个Web应用程序,并通过http2提供它。然而,当我在Google Chrome(版本59.0.3071.115(官方版本)(64位))的开发者工具中分析网络时,很明显多路复用不起作用,因为只有6个活动连接(与http1.1一样),其余的连接都在排队等待。

为什么会这样?或者我的期望不正确吗?

截图(您可以看到协议是http2):

Chrome's network tab showing only 6 active connections with the rest queued in spite of using http2

更新 #1:

  • 后端运行在 nginx 1.13 上;
  • 我正在使用自定义模块加载器,它通过创建带有 async 属性的脚本标签来一次性加载所有脚本;
  • 截图显示,对于第8行及其后面的内容,浏览器已经收到了下载资源的请求,但是白色部分表明这些脚本已排队,只有在可用插槽时才会实际开始下载(请看第2、3和4行完成后,第8、7和9行开始加载;同样,第11、12、13行和第5、6、7行也是如此)。

1
你能否提供一个最小化的例子来重现这个问题并分享给我们? - Frederik Deweerdt
1
@FrederikDeweerdt 感谢您的回复;我无法展示当前环境,但我会为此设置另一个环境,最简化以确认问题。 - Kirill G.
2个回答

12

我认为这是Chrome的一个 bug,或者至少是一种不必要的限制。

这很容易测试。

我创建了一个简单的示例 HTML 文件,它会下载同一个 JavaScript 文件的 25 个副本(通过查询参数使其看起来像是不同的资源):

<!DOCTYPE HTML>
<html>
<head>
        <title>Test for Lots of JS files</title>
        <meta name="robots" content="noindex">
<body>
</body>
        <h1>This is a test for Lots of JS files</h1>

        <script src="/assets/js/test.js?v=01"></script>
        <script src="/assets/js/test.js?v=02"></script>
        <script src="/assets/js/test.js?v=03"></script>
        <script src="/assets/js/test.js?v=04"></script>
        <script src="/assets/js/test.js?v=05"></script>
        <script src="/assets/js/test.js?v=06"></script>
        <script src="/assets/js/test.js?v=07"></script>
        <script src="/assets/js/test.js?v=08"></script>
        <script src="/assets/js/test.js?v=09"></script>
        <script src="/assets/js/test.js?v=10"></script>
        <script src="/assets/js/test.js?v=11"></script>
        <script src="/assets/js/test.js?v=12"></script>
        <script src="/assets/js/test.js?v=13"></script>
        <script src="/assets/js/test.js?v=14"></script>
        <script src="/assets/js/test.js?v=15"></script>
        <script src="/assets/js/test.js?v=16"></script>
        <script src="/assets/js/test.js?v=17"></script>
        <script src="/assets/js/test.js?v=18"></script>
        <script src="/assets/js/test.js?v=19"></script>
        <script src="/assets/js/test.js?v=20"></script>
        <script src="/assets/js/test.js?v=21"></script>
        <script src="/assets/js/test.js?v=22"></script>
        <script src="/assets/js/test.js?v=23"></script>
        <script src="/assets/js/test.js?v=24"></script>
        <script src="/assets/js/test.js?v=25"></script>

</html>

我接着做了同样的事情,但加上了async属性,以防万一Chrome在处理Javascript时决定阻止下载:

        <script src="/assets/js/test.js?v=01" async=""></script>
        <script src="/assets/js/test.js?v=02" async=""></script>
        ....etc.

再次相同,但使用defer属性:

        <script src="/assets/js/test.js?v=01" defer=""></script>
        <script src="/assets/js/test.js?v=02" defer=""></script>
        ....etc.

/assets/js/test.js文件是空的。因此,除了浏览器添加的依赖项之外,不会有执行延迟或其他依赖项。

我看到了一些有趣的结果!这都是使用Chrome 60.0.3112.78或60.0.3112.101,并且我正在使用Apache,但看到与您在Nginx上看到的相同结果。

使用HTTP/2服务器,我们看到以下结果:

使用普通的script标签,所有脚本都并行加载(但可能按顺序执行)。不存在HTTP/1.1下的6个连接限制: Javascript with no async or defer

使用异步script标签,脚本以6个为一组并行加载-与您提到的完全相同: Javascript with async

点击它们可以看到它们通过HTTP/2下载。

使用延迟script标签时,结果与使用异步标签相同-限制同时进行6次下载。

这没有意义- Chrome限制了您的JavaScript下载,但只有在使用异步或延迟模式来提高下载不阻止呈现的情况下才会出现!

正如sbordet所述,在视口中的图像上也没有发生同样的事情-因此Chrome上的多路复用确实有效,但它看起来对于异步或延迟模式下的JavaScript受到无谓的限制。如果您考虑不再在HTTP/2下捆绑脚本,则这是一个真正的限制,许多人建议您不再需要这样做。

Firefox和Edge上不会发生相同的情况。但在Opera(基于Chromium的浏览器)上会发生。

这就是坏消息。好消息是他们“可能”已经解决了这个问题。当我尝试使用Chrome Canary(62.0.3190.0)时,我无法重复此行为。但是,当我在Canary中使用Web Page Test(其在用户代理字符串中提供了62.0.3190.1,因此应该几乎相同),它是可重复的,因此并不确定他们是否真的解决了这个问题...

我已经向Chrome团队报告了这个错误,所以将看看他们会说什么:https://bugs.chromium.org/p/chromium/issues/detail?id=757191

总的来说,HTTP/2在服务器和客户端上似乎还处于一种不稳定状态,因为双方都调整其实现以获取对这个仍然相对较新的协议的最佳使用。尽管如此,这让人惊讶的是见到Chrome遇到这个问题,因为谷歌用他们的SDPY实现(HTTP/2是基于此的)启动了这个功能,所以您会期望他们走在前面而不是落后...

**更新**

Chrome团队回复并确认这是Chrome中当前实现的HTTP/2限制。当同时调用多个资源时,他们发现性能问题,因为HTTP/2允许,因此限制非关键


1
添加了来自Chrome团队的反馈。 - Barry Pollard
1
从2020年问候您,Chrome团队还没有解决这个问题 :( - Gihan
大家好,来自2021年的问候。有人能确认这个问题是否已经解决了吗? - legalimpurity

1
Chrome决定在使用HTTP/2时限制多路复用的原因可能有多种。
例如,在下载具有大量图像的页面时,行为会因图像是否在浏览器视口中显示而大不相同。
您正在下载的文档是脚本,脚本可能会阻塞,或者彼此依赖,或以其他方式改变浏览器下载资源的方式。
事实上,如果您去HTTP/2的在线示例(如https://http2.golang.org/gophertiles?latency=0),您将看到Chrome确实很好地多路复用了图像的下载(但仅当它们在视口中显示时)。
因此,对于您的情况,可能是与脚本有关;也许它们彼此依赖,这就是Chrome不能同时多路复用超过6个的原因。
我不会感到惊讶,如果这是JavaScript加载程序的限制,它们假设HTTP/1.1并且现在已经过时了HTTP/2。
您可以使用Chrome开发人员工具中的“性能”选项卡来了解更多关于您的页面性能的信息。
你还需要查看Page Speed等工具,以了解如何优化页面。
总的来说,我认为这不是Chrome实现HTTP/2的问题,而是你的应用程序/脚本中没有针对HTTP/2进行优化。

谢谢回复,但我认为你的任何评论都不适用于我的情况。请查看原帖中的更新#1。此外,页面速度没有给出任何有意义的结果(我得到了100/100)。 - Kirill G.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接