对具有以下标题的文档的响应进入 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 选项卡如下所示:
我已经测试过
Type
设置正确,看起来没问题。可能是什么问题?连续请求(启用 chrome 缓存)也会产生类似的结果:
可能有什么问题?我很确定请求不应该重复
@编辑
我尝试在没有 Nginx 的情况下进行服务器推送(直接与 Node.js 后端对话,而不是后端为 Nginx 附加链接 header )。它可以正常工作。使用Nginx时出现问题。
顺便提一句。我确实知道不应通过服务器推送推送所有内容,尤其是图像,但我这样做只是为了进行清晰的测试。如果您仔细观察,似乎只有脚本会被复制并且图片仅下载一次。
最佳答案
问题的核心其实是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 一起工作正常:
希望 Nginx 修路
http2_push_preload
工作,并允许更多的控制。顺便说一句,我认为 Chrome 无论如何都应该处理这个问题,而不是下载 2 倍的字节数。
关于google-chrome - HTTP/2 服务器推送导致重复请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59601465/