Google Chrome 不与 http2 进行多路复用
Google Chrome does not do multiplexing with http2
我正在构建一个网络应用程序并通过 http2 为它提供服务。然而,当我在 Google Chrome(版本 59.0.3071.115(官方构建)(64 位))的开发人员工具中分析网络时,很明显多路复用不起作用,因为只有 6 个活动连接(如 http1.1)和其余连接排队。
这是为什么?还是我的期望不正确?
截图(可以看到协议是http2):
更新 #1:
- 后台运行在nginx 1.13;
- 我正在使用一次加载所有脚本的自定义模块加载器(通过在循环中创建具有
async
属性的脚本标记);
- 屏幕截图显示第 8 行及以后的浏览器已收到开始下载资源的请求,但该行的白色部分显示此脚本已排队并且只有在插槽可用时才开始实际下载(请参阅如何行一旦第 2、3 和 4 行完成,8、7 和 9 开始加载;第 11、12、13 和 5、6、7 行也是如此。
Chrome 在使用 HTTP/2 时决定限制多路复用可能有多种原因。
例如,当您下载包含大量图像的页面时,行为会非常不同,具体取决于图像是否在浏览器视口中显示。
您正在下载的文件是脚本,脚本可能会阻塞,或者相互依赖,或者以其他方式改变浏览器下载资源的方式。
事实上,如果您查看 HTTP/2 的在线示例,例如 https://http2.golang.org/gophertiles?latency=0,您会发现 Chrome 确实很好地多路复用了图像下载(但前提是它们显示在视口中)。
因此,对于您的情况,可能与脚本有关;也许它们相互依赖,这就是为什么 Chrome 不能同时将它们复用超过 6 个。
如果这是假设 HTTP/1.1 并且现在已被 HTTP/2.
淘汰的 JavaScript 加载器的限制,我不会感到惊讶
您可以使用 Chrome 开发人员工具中的 "Performance" 选项卡来了解有关页面性能的更多信息。
您还想查看 Page Speed 等工具,这些工具可让您了解如何优化页面。
总而言之,我不认为 Chrome 实现 HTTP/2 的方式有问题,而是 application/scripts 中未针对 HTTP/2 优化的内容.
我认为这是 Chrome 中的一个错误,或者至少是一个不必要的限制。
这很容易测试。
我创建了一个简单的示例 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>
然后我做了同样的事情,但添加了异步属性,以防 Chrome 决定在处理 Javascript:
时阻止下载
<script src="/assets/js/test.js?v=01" async=""></script>
<script src="/assets/js/test.js?v=02" async=""></script>
....etc.
再次相同,但具有延迟属性:
<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 个连接限制:
使用异步 script
标记,脚本以 6 个为一组并行加载 - 正如您所说:
点击它们显示它们是通过 HTTP/2 下载的。
使用 defer script
标签,脚本与使用 async 标签的结果相同 - 一次限制为 6 次下载。
这没有意义 - Chrome 正在限制您的 Javascript 下载,但前提是您使用 async 或 defer 来改进您的下载以阻止渲染!
正如 sbordet 所述,视口中的图像不会发生同样的情况 - 因此多路复用确实适用于 Chrome,它只是在异步或延迟模式下似乎对 Javascript 没有必要的限制。这是一个真正的限制,如果您考虑不再将脚本捆绑在一起 HTTP/2,因为许多人建议您不再需要这样做。
在 Firefox 和 Edge 上不会发生同样的情况。尽管它确实发生在 Opera(基于 Chromium 的浏览器)上。
这就是坏消息。好消息是他们 "may" 已经修复了它。当我尝试 Chrome Canary (62.0.3190.0) 时,我无法重复这种行为。但是,当我使用带有 Canary 的网页测试时(它在用户代理字符串中给出 62.0.3190.1,因此应该几乎相同)它 是 可重复的,所以不能 100% 确定他们有毕竟修好了...
为此向 Chrome 团队提出了一个错误,所以看看他们怎么说:https://bugs.chromium.org/p/chromium/issues/detail?id=757191
总而言之,HTTP/2 目前在服务器和客户端上似乎都在不断变化,因为双方都在调整和调整他们的实现以充分利用这个相对较新的协议。尽管如此,看到 Chrome 受到影响仍然令人惊讶,因为 Google 从他们的 SDPY 实施开始(HTTP/2 在很大程度上基于此)所以你会期望他们走在曲线的前面不落后...
** 更新 **
Chrome 团队返回并确认这是 Chrome 中 HTTP/2 当前实施的限制。当 HTTP/2 允许同时调用许多资产时,他们发现性能问题,因此将非关键项目(包括 async/defer 和视口中不可见的项目)限制为 HTTP/1.1限制为 6.
尽管 HTTP/2 有在请求发送后进行优先级排序的概念,但性能问题在它们被优先级排序和发送之前就已经被发现(例如检查缓存、cookies...等)所以 HTTP/2 优先级在这里没有帮助。
他们希望在未来改进这一点。
所以我猜我是对的,这是一个实施问题,因为我们已经习惯了新的 HTTP/2 世界并且必须为此优化我们的浏览器和服务器!
我正在构建一个网络应用程序并通过 http2 为它提供服务。然而,当我在 Google Chrome(版本 59.0.3071.115(官方构建)(64 位))的开发人员工具中分析网络时,很明显多路复用不起作用,因为只有 6 个活动连接(如 http1.1)和其余连接排队。
这是为什么?还是我的期望不正确?
截图(可以看到协议是http2):
更新 #1:
- 后台运行在nginx 1.13;
- 我正在使用一次加载所有脚本的自定义模块加载器(通过在循环中创建具有
async
属性的脚本标记); - 屏幕截图显示第 8 行及以后的浏览器已收到开始下载资源的请求,但该行的白色部分显示此脚本已排队并且只有在插槽可用时才开始实际下载(请参阅如何行一旦第 2、3 和 4 行完成,8、7 和 9 开始加载;第 11、12、13 和 5、6、7 行也是如此。
Chrome 在使用 HTTP/2 时决定限制多路复用可能有多种原因。
例如,当您下载包含大量图像的页面时,行为会非常不同,具体取决于图像是否在浏览器视口中显示。
您正在下载的文件是脚本,脚本可能会阻塞,或者相互依赖,或者以其他方式改变浏览器下载资源的方式。
事实上,如果您查看 HTTP/2 的在线示例,例如 https://http2.golang.org/gophertiles?latency=0,您会发现 Chrome 确实很好地多路复用了图像下载(但前提是它们显示在视口中)。
因此,对于您的情况,可能与脚本有关;也许它们相互依赖,这就是为什么 Chrome 不能同时将它们复用超过 6 个。
如果这是假设 HTTP/1.1 并且现在已被 HTTP/2.
淘汰的 JavaScript 加载器的限制,我不会感到惊讶您可以使用 Chrome 开发人员工具中的 "Performance" 选项卡来了解有关页面性能的更多信息。
您还想查看 Page Speed 等工具,这些工具可让您了解如何优化页面。
总而言之,我不认为 Chrome 实现 HTTP/2 的方式有问题,而是 application/scripts 中未针对 HTTP/2 优化的内容.
我认为这是 Chrome 中的一个错误,或者至少是一个不必要的限制。
这很容易测试。
我创建了一个简单的示例 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>
然后我做了同样的事情,但添加了异步属性,以防 Chrome 决定在处理 Javascript:
时阻止下载 <script src="/assets/js/test.js?v=01" async=""></script>
<script src="/assets/js/test.js?v=02" async=""></script>
....etc.
再次相同,但具有延迟属性:
<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 个连接限制:
使用异步 script
标记,脚本以 6 个为一组并行加载 - 正如您所说:
点击它们显示它们是通过 HTTP/2 下载的。
使用 defer script
标签,脚本与使用 async 标签的结果相同 - 一次限制为 6 次下载。
这没有意义 - Chrome 正在限制您的 Javascript 下载,但前提是您使用 async 或 defer 来改进您的下载以阻止渲染!
正如 sbordet 所述,视口中的图像不会发生同样的情况 - 因此多路复用确实适用于 Chrome,它只是在异步或延迟模式下似乎对 Javascript 没有必要的限制。这是一个真正的限制,如果您考虑不再将脚本捆绑在一起 HTTP/2,因为许多人建议您不再需要这样做。
在 Firefox 和 Edge 上不会发生同样的情况。尽管它确实发生在 Opera(基于 Chromium 的浏览器)上。
这就是坏消息。好消息是他们 "may" 已经修复了它。当我尝试 Chrome Canary (62.0.3190.0) 时,我无法重复这种行为。但是,当我使用带有 Canary 的网页测试时(它在用户代理字符串中给出 62.0.3190.1,因此应该几乎相同)它 是 可重复的,所以不能 100% 确定他们有毕竟修好了...
为此向 Chrome 团队提出了一个错误,所以看看他们怎么说:https://bugs.chromium.org/p/chromium/issues/detail?id=757191
总而言之,HTTP/2 目前在服务器和客户端上似乎都在不断变化,因为双方都在调整和调整他们的实现以充分利用这个相对较新的协议。尽管如此,看到 Chrome 受到影响仍然令人惊讶,因为 Google 从他们的 SDPY 实施开始(HTTP/2 在很大程度上基于此)所以你会期望他们走在曲线的前面不落后...
** 更新 **
Chrome 团队返回并确认这是 Chrome 中 HTTP/2 当前实施的限制。当 HTTP/2 允许同时调用许多资产时,他们发现性能问题,因此将非关键项目(包括 async/defer 和视口中不可见的项目)限制为 HTTP/1.1限制为 6.
尽管 HTTP/2 有在请求发送后进行优先级排序的概念,但性能问题在它们被优先级排序和发送之前就已经被发现(例如检查缓存、cookies...等)所以 HTTP/2 优先级在这里没有帮助。
他们希望在未来改进这一点。
所以我猜我是对的,这是一个实施问题,因为我们已经习惯了新的 HTTP/2 世界并且必须为此优化我们的浏览器和服务器!