Google Chrome浏览器不与http2进行多路复用

Kir*_* G. 6 google-chrome multiplexing http2

我正在构建一个webapp,并通过http2进行服务。但是,当我在Google Chrome浏览器(版本59.0.3071.115(正式版本)(64位))的开发人员工具中分析网络时,很明显,多路复用不起作用,因为只有6个活动连接(例如http1.1)其余的连接排队。

为什么是这样?还是我的期望不正确?

屏幕截图(您可以看到该协议为http2):

Chrome浏览器的“网络”标签仅显示6个活动的连接,其余的均使用http2进行排队

更新#1:

  • 后端在nginx 1.13上运行;
  • 我正在使用自定义模块加载器,该加载器一次加载所有脚本(通过async在循环中创建带有属性的脚本标签);
  • 屏幕截图显示,对于第8行及以后的浏览器,浏览器已收到开始下载资源的请求,但是该行的白色部分显示此脚本已排队,并且仅在插槽可用时才开始实际下载(请参见第8、7和9行)一旦完成第2、3和4行,便开始加载;第11、12、13和5、6、7行也是如此。

Bar*_*ard 7

我认为这是Chrome中的错误,或者至少是不必要的限制。

这很容易测试。

我创建了一个简单的示例HTML文件,该文件下载了25个相同的javascript文件的副本(带有查询参数,使其看起来像不同的资源):

<!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>
Run Code Online (Sandbox Code Playgroud)

I then did the same, but adding the async attribute, in case Chrome decide to block downloading while processing the Javascript:

        <script src="/assets/js/test.js?v=01" async=""></script>
        <script src="/assets/js/test.js?v=02" async=""></script>
        ....etc.
Run Code Online (Sandbox Code Playgroud)

and the same again but with the defer attribute:

        <script src="/assets/js/test.js?v=01" defer=""></script>
        <script src="/assets/js/test.js?v=02" defer=""></script>
        ....etc.
Run Code Online (Sandbox Code Playgroud)

The /assets/js/test.js file was empty. So there would be no execution delays, nor dependencies except those that the browser added.

I saw some interesting results! This is all with Chrome 60.0.3112.78 or 60.0.3112.101, and I'm using Apache, but saw same results as you saw for Nginx.

With an HTTP/2 server we see the following results:

With a plain script tag all the scripts are loaded in parallel (but presumably executed in order). There is no 6 connection limit as under HTTP/1.1: 没有异步或延迟的Javascript

With an async script tag the scripts are loaded in parallel in groups of 6 - exactly as you noted: 带有异步的Javascript

Clicking on them shows they WERE downloaded over HTTP/2.

With a defer script tag the scripts is the same as the results for using the async tag - a throttling to 6 downloads at a time.

This does not make sense - Chrome is restricting your Javascript downloads, but only if you use async or defer to improve your downloads from blocking rendering!

As sbordet stated, the same does not happen for images in the viewport - so multiplexing DOES work on Chrome, it just appears to be needlessly limited for Javascript in async or defer mode. This is a real limitation, if you are considering not bundling scripts together any more under HTTP/2, as many advise you no longer need to do.

The same does not happen on Firefox, nor Edge. Though it does happen on Opera (a Chromium based browser).

So that's the bad news. The good news is that they "may" have fixed it. When I try Chrome Canary (62.0.3190.0) I can't repeat this behaviour. However when I use Web Page Test with Canary (which it gives 62.0.3190.1 in the user agent string, so should be practically the same) it is repeatable, so not 100% sure they have fixed this after all...

Have raised a bug with the Chrome team for this so will see what they say: https://bugs.chromium.org/p/chromium/issues/detail?id=757191

All in all, HTTP/2 on both server and client does seem a little in flux at the moment, as both sides tweak and tune their implementations to get optimal use out of this still relatively new protocol. Still, it's surprising to see Chrome hit with this since Google started this off with their SDPY implementation (which HTTP/2 is heavily based upon) so you would expect them to be ahead of the curve not behind...

** Update **

Chrome team got back and confirm this is a restriction of current implementation of HTTP/2 in Chrome. They were seeing performance issues when many assets very called at once, as HTTP/2 allows, so restrict non-critical items (including async/defer and items not visible in the viewport) to HTTP/1.1 limit of 6.

即使HTTP / 2具有在请求发送之后对请求进行优先级排序的概念,但是在对请求进行优先级排序和发送之前(例如,检查缓存,Cookie等),还是会看到性能问题,因此HTTP / 2优先级排序在这里没有帮助。

他们希望将来能改善这一点。

因此,我猜对了,这是一个实现问题,因为我们已经习惯了新的HTTP / 2世界,并且必须为此优化浏览器和服务器!