google-chrome - HTTP/2 服务器推送导致重复请求

标签 google-chrome nginx chromium http2 server-push

对具有以下标题的文档的响应进入 Nginx:

link: </picture.jpg>; as=image; rel=preload
link: </_next/static/chunks/commons.4e96503c89eea0476d3e.module.js>; as=script; rel=preload
link: </_next/static/runtime/main-3c17cb16bbbc3efc4bb5.module.js>; as=script; rel=preload
link: </_next/static/runtime/webpack-0b10894b69bf5a718e01.module.js>; as=script; rel=preload
link: </_next/static/Q53NXtgLT1rgpqOOsVV6Q/pages/_app.module.js>; as=script; rel=preload
link: </_next/static/Q53NXtgLT1rgpqOOsVV6Q/pages/index.module.js>; as=script; rel=preload

在 HTTP/2 服务器推送的帮助下,请求被推送到客户端,但 6 个请求中有 5 个下载两次(一次是推送,一次是由文档触发)。
Chrome Dev Tools 中的 Network 选项卡如下所示:
network graph
我已经测试过 Type设置正确,看起来没问题。可能是什么问题?

连续请求(启用 chrome 缓存)也会产生类似的结果:
network graph with cache enabled

可能有什么问题?我很确定请求不应该重复

@编辑
我尝试在没有 Nginx 的情况下进行服务器推送(直接与 Node.js 后端对话,而不是后端为 Nginx 附加链接 header )。它可以正常工作。使用Nginx时出现问题。
push via nodejs

顺便提一句。我确实知道不应通过服务器推送推送所有内容,尤其是图像,但我这样做只是为了进行清晰的测试。如果您仔细观察,似乎只有脚本会被复制并且图片仅下载一次。

最佳答案

问题的核心其实是Chromium。从我所见,这件事仅在 Chromium 中失败。

Nginx 的问题在于 http2_push_preload 的实现.

Nginx 寻找的是带有 Link: </resource>; as=type; rel=preload 的 header .它读取它并通过推送提供文件,不幸的是当浏览器(我实际上只测试了 Chrome)接收到带有 Link 的文档时。 header 和 Push it 冲突导致显着的减速并下载在解析文档时看到的资源。

# This results in HTTP/2 Server Push and the requests get duplicated due to the `Link` headers that were passed along
location / {
    proxy_pass http://localhost:3000;
    http2_push_preload on;
}

# This results in Resource Hints getting triggered in the browser.
location / {
    proxy_pass http://localhost:3000;
}

# This results in a regular HTTP/2 (no push)
location / {
    proxy_pass http://localhost:3000;
    http2_push_preload on;
    proxy_hide_header link;
}

# This result in a valid HTTP/2 Server Push (proper)
location / {
    proxy_pass http://localhost:3000;
    http2_push /commons.4e96503c89eea0476d3e.module.js;
    http2_push /index.module.js;
    http2_push /_app.module.js;
    http2_push /webpack-0b10894b69bf5a718e01.module.js;
    http2_push /main-3c17cb16bbbc3efc4bb5.module.js;
}

看来 Nginx 还不能很好地使用此功能...

如果我能删除 Link标题和使用 http2_push_preload ...

无论如何,我让它与 H2O 的用法一起工作
H2O 确实让我删除了 header ,同时保留了 HTTP/2 服务器推送
// h2o.conf
  [...]
  proxy.reverse.url: "http://host.docker.internal:3000/"
  header.unset: "Link"

与 H2O 一起工作正常:
H2O success
希望 Nginx 修路http2_push_preload工作,并允许更多的控制。

顺便说一句,我认为 Chrome 无论如何都应该处理这个问题,而不是下载 2 倍的字节数。

关于google-chrome - HTTP/2 服务器推送导致重复请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59601465/

相关文章:

google-chrome - 无法在 Chrome 设备模式下更新模拟设备列表

javascript - 如何在 Chrome 扩展中编写一些 javascript,以便如果运行 javascript 代码,并且用户按下后退按钮,它会返回两次?

nginx - 带有 nginx 的 FastAPI 不提供 HTTPS 中的静态文件

mysql - 部署rails应用程序时的nginx错误消息

php - 阻止 nginx 重定向到 index.php

node.js - 如何使用 headless : true? 使用 puppeteer 下载文件

javascript - 如何在浏览器中运行我的 nw-js 应用程序?

automated-tests - TestCafe chromium 测试作为 docker 构建的一部分运行

javascript - Google Chrome console.log 乱序?

javascript - 脚本可以使用 Greasemonkey 但不适用于 Tampermonkey。是因为 jQuery $.get 吗?