【问题标题】:Using http2_push with nginX in conjunction with HAProxy does not work将 http2_push 与 nginX 与 HAProxy 结合使用不起作用
【发布时间】:2018-10-05 22:49:35
【问题描述】:

在 HaProxy 后面配置 nginX 时,我无法让 HTTP/2 推送工作。然而,当 nginX 被网络浏览器直接点击时,它确实工作。

已经做了很多研究,但没有找到任何提示。希望有人知道我做错了什么。请参阅下面的配置和进一步的观察。

配置

相关的HaProxy(1.8.7版)配置由:

前端应用名称 绑定 *:443 ssl crt certificate.pem alpn h2,http/1.1 模式 tcp 如果 { ssl_fc_alpn -i h2 } 使用_backend app-http2 default_backend 应用程序 后端应用程序-http2 模式 tcp 服务器 lamp2 127.0.0.1:8002 检查发送代理

而相关的nginX(1.14.0版本)配置如下:

http { # 这是我想用的 服务器 { 听 8002 http2 proxy_protocol; 服务器名称 _; 根 /usr/share/nginx/html; 地点 / { http2_push /image.jpg; } } # 这个可以直接访问;并且*确实*工作 服务器 { 听 8004 http2 ssl; ssl_certificate 证书.pem; ssl_certificate_key private.key; 服务器名称 _; 根 /usr/share/nginx/html; 地点 / { http2_push /image.jpg; } } }

观察

  • 在 nginx 日志中,我可以验证访问内容的两种方式都使用 HTTP2。
  • 当我使用 Chrome 访问页面时,我可以看到 push is 仅在直接访问 nginX 时使用

2018 年 5 月 9 日更新 还是没有解决。但人们似乎同意这是一个错误。我在他们的问题跟踪器上打开了一个问题:https://trac.nginx.org/nginx/ticket/1549#ticket

2018 年 4 月 26 日更新

看来问题不仅仅是 http2 推送。如果我记录$scheme nginX 变量,它总是设置为http。从 http2 访问 http 时都一样。

所以这显然是个问题。但是我不确定如何解决这个问题。 Haproxy 工作在 tcp 模式;因此可能不会做错任何事。

一个相关(但可能已过时)的 Stack Overflow 主题是 nginx $scheme variable behind load balancer。但这个答案无助于解决这个问题!

2018 年 4 月 25 日更新

还是不行。但更近了一步。在两者上运行 nghttp2,结果如下所示。

两者似乎都嵌入了 /image.jpg 资源。但是通过 haproxy 的方案设置为 http;而不是https。正如在这个差异中看到的那样:

我认为是因为这个; Chrome 不会使用这个推送的资源。但是我不确定是什么原因造成的!

有人知道吗?


两个命令的完整输出:

nghttp -nv https://127.0.0.1:8004/ [ 0.001] 已连接 协商协议:h2 [0.003]发送设置帧 (niv=2) [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100] [SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535] [0.003]发送优先帧 (dep_stream_id=0,权重=201,独占=0) [0.003]发送优先帧 (dep_stream_id=0,权重=101,独占=0) [0.003]发送优先帧 (dep_stream_id=0,权重=1,独占=0) [0.003]发送优先帧 (dep_stream_id=7,权重=1,排他=0) [0.003]发送优先帧 (dep_stream_id=3,权重=1,排他=0) [0.003]发送标题帧 ; END_STREAM | END_HEADERS |优先 (padlen=0,dep_stream_id=11,权重=16,排他=0) ;打开新流 :方法:获取 :小路: / :方案:https :权威:127.0.0.1:8004 接受: */* 接受编码:gzip,放气 用户代理:nghttp2/1.25.0 [ 0.003] 接收设置帧 (niv=3) [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):128] [SETTINGS_INITIAL_WINDOW_SIZE(0x04):65536] [SETTINGS_MAX_FRAME_SIZE(0x05):16777215] [0.003] 接收窗口更新帧 (window_size_increment=2147418112) [0.003]发送设置帧 ;确认 (niv=0) [ 0.003] 接收设置帧 ;确认 (niv=0) [0.003]recv(stream_id=13):方法:获取 [0.003]recv(stream_id=13):路径:/image.jpg [0.003] recv (stream_id=13):scheme: https [0.003] recv (stream_id=13):authority: 127.0.0.1:8004 [0.003] recv (stream_id=13) 接受编码:gzip,放气 [0.003]recv(stream_id=13)用户代理:nghttp2/1.25.0 [0.003]接收PUSH_PROMISE帧 ; END_HEADERS (padlen=0,promise_stream_id=2) [0.003]recv(stream_id=13):状态:200 [0.003]recv(stream_id=13)服务器:nginx/1.14.0 [0.003] recv (stream_id=13) 日期:2018 年 4 月 25 日星期三 15:08:26 GMT [0.003]recv(stream_id=13)内容类型:文本/html [0.003]recv(stream_id=13)内容长度:638 [0.003] recv (stream_id=13) 最后修改时间:2018 年 4 月 25 日星期三 11:42:58 GMT [0.003]recv(stream_id=13)etag:“5ae069c2-27e” [0.003] recv (stream_id=13) 接受范围:字节 [0.003]接收标题帧 ; END_HEADERS (padlen=0) ;第一个响应标头 [0.004]接收数据帧 ; END_STREAM [0.004]recv(stream_id=2):状态:200 [0.004]recv(stream_id=2)服务器:nginx/1.14.0 [0.004] recv (stream_id=2) 日期:2018 年 4 月 25 日星期三 15:08:26 GMT [0.004] recv (stream_id=2) 内容类型:图像/jpeg [0.004]recv(stream_id=2)内容长度:182884 [0.004] recv (stream_id=2) 最后修改时间:2016 年 6 月 18 日星期六 15:42:26 GMT [0.004]recv(stream_id=2)etag:“57656be2-2ca64” [0.004] recv (stream_id=2) 接受范围:字节 [0.004]接收标题帧 ; END_HEADERS (padlen=0) ;第一个推送响应头 [0.004]接收数据帧 [0.004]接收数据帧 [0.004]接收数据帧 [0.004]接收数据帧 [0.004]接收数据帧 [0.004] 发送 WINDOW_UPDATE 帧 (window_size_increment=33248) [0.004] 发送 WINDOW_UPDATE 帧 (window_size_increment=32768) [0.004]接收数据帧 [0.004]接收数据帧 [0.004]接收数据帧 [0.046]接收数据帧 [0.046]接收数据帧 [0.046]接收数据帧 [0.046]接收数据帧 [0.046]接收数据帧 [0.046]发送WINDOW_UPDATE帧 (window_size_increment=32925) [0.046]发送WINDOW_UPDATE帧 (window_size_increment=32767) [0.046]接收数据帧 [0.046]发送WINDOW_UPDATE帧 (window_size_increment=32768) [0.046]发送WINDOW_UPDATE帧 (window_size_increment=32768) [0.046]接收数据帧 [0.090]接收数据帧 [0.090]接收数据帧 [0.090]接收数据帧 [0.090]接收数据帧 [0.090]接收数据帧 [0.090]接收数据帧 [0.090]接收数据帧 [0.090] 发送 WINDOW_UPDATE 帧 (window_size_increment=32767) [0.090] 发送 WINDOW_UPDATE 帧 (window_size_increment=32767) [0.090] 发送 WINDOW_UPDATE 帧 (window_size_increment=32768) [0.090] 发送 WINDOW_UPDATE 帧 (window_size_increment=32768) [0.134]接收数据帧 [0.134]接收数据帧 [0.134]接收数据帧 ; END_STREAM [0.134]发送GOAWAY帧 (last_stream_id=2, error_code=NO_ERROR(0x00), opaque_data(0)=[])

nghttp -nv https://127.0.0.1:8002/ [ 0.001] 已连接 协商协议:h2 [0.003]发送设置帧 (niv=2) [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100] [SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535] [0.003]发送优先帧 (dep_stream_id=0,权重=201,独占=0) [0.003]发送优先帧 (dep_stream_id=0,权重=101,独占=0) [0.003]发送优先帧 (dep_stream_id=0,权重=1,独占=0) [0.003]发送优先帧 (dep_stream_id=7,权重=1,排他=0) [0.003]发送优先帧 (dep_stream_id=3,权重=1,排他=0) [0.003]发送标题帧 ; END_STREAM | END_HEADERS |优先 (padlen=0,dep_stream_id=11,权重=16,排他=0) ;打开新流 :方法:获取 :小路: / :方案:https :权威:127.0.0.1:8002 接受: */* 接受编码:gzip,放气 用户代理:nghttp2/1.25.0 [ 0.003] 接收设置帧 (niv=3) [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):128] [SETTINGS_INITIAL_WINDOW_SIZE(0x04):65536] [SETTINGS_MAX_FRAME_SIZE(0x05):16777215] [0.003] 接收窗口更新帧 (window_size_increment=2147418112) [0.003]发送设置帧 ;确认 (niv=0) [ 0.004] 接收设置帧 ;确认 (niv=0) [0.004]recv(stream_id=13):方法:获取 [0.004]recv(stream_id=13):路径:/image.jpg [0.004]recv(stream_id=13):方案:http [0.004] recv (stream_id=13):authority: 127.0.0.1:8002 [0.004]recv(stream_id=13)接受编码:gzip,放气 [0.004]recv(stream_id=13)用户代理:nghttp2/1.25.0 [0.004]recv PUSH_PROMISE 帧 ; END_HEADERS (padlen=0,promise_stream_id=2) [0.004]recv(stream_id=13):状态:200 [0.004]recv(stream_id=13)服务器:nginx/1.14.0 [0.004] recv (stream_id=13) 日期:2018 年 4 月 25 日星期三 15:08:45 GMT [0.004]recv(stream_id=13)内容类型:文本/html [0.004]recv(stream_id=13)内容长度:638 [0.004] recv (stream_id=13) 最后修改时间:2018 年 4 月 25 日星期三 11:42:58 GMT [0.004]recv(stream_id=13)etag:“5ae069c2-27e” [0.004]recv(stream_id=13)接受范围:字节 [0.004]接收标题帧 ; END_HEADERS (padlen=0) ;第一个响应标头 [0.004]接收数据帧 ; END_STREAM [0.004]recv(stream_id=2):状态:200 [0.004]recv(stream_id=2)服务器:nginx/1.14.0 [0.004] recv (stream_id=2) 日期:2018 年 4 月 25 日星期三 15:08:45 GMT [0.004] recv (stream_id=2) 内容类型:图像/jpeg [0.004]recv(stream_id=2)内容长度:182884 [0.004] recv (stream_id=2) 最后修改时间:2016 年 6 月 18 日星期六 15:42:26 GMT [0.004]recv(stream_id=2)etag:“57656be2-2ca64” [0.004] recv (stream_id=2) 接受范围:字节 [0.004]接收标题帧 ; END_HEADERS (padlen=0) ;第一个推送响应头 [0.004]接收数据帧 [0.004]接收数据帧 [0.004]接收数据帧 [0.004]接收数据帧 [0.004]接收数据帧 [0.004] 发送 WINDOW_UPDATE 帧 (window_size_increment=33406) [0.004] 发送 WINDOW_UPDATE 帧 (window_size_increment=32768) [0.004]接收数据帧 [0.004]接收数据帧 [0.004]接收数据帧 [0.044]接收数据帧 [0.044] 发送 WINDOW_UPDATE 帧 (window_size_increment=32767) [0.044] 发送 WINDOW_UPDATE 帧 (window_size_increment=32767) [0.044]接收数据帧 [0.044]接收数据帧 [0.045]接收数据帧 [0.045]接收数据帧 [0.045] 发送 WINDOW_UPDATE 帧 (window_size_increment=32768) [0.045] 发送 WINDOW_UPDATE 帧 (window_size_increment=32768) [0.045]接收数据帧 [0.045]接收数据帧 [0.045]接收数据帧 [0.045]接收数据帧 [0.045] 发送 WINDOW_UPDATE 帧 (window_size_increment=32767) [0.045] 发送 WINDOW_UPDATE 帧 (window_size_increment=32767) [0.045]接收数据帧 [0.046]接收数据帧 [0.046]接收数据帧 [0.046]接收数据帧 [0.046]发送WINDOW_UPDATE帧 (window_size_increment=32768) [0.046]发送WINDOW_UPDATE帧 (window_size_increment=32768) [0.046]接收数据帧 [0.046]接收数据帧 [0.046]接收数据帧 ; END_STREAM [0.046]发送GOAWAY帧 (last_stream_id=2, error_code=NO_ERROR(0x00), opaque_data(0)=[])

【问题讨论】:

  • 你能用nghttp重现这个问题吗? nghttp -nv https://127.0.0.1:8002nghttp -nv https://127.0.0.1:8004 的输出是什么? chrome://net-internals/#http2 中的 chrome 日志呢?
  • 谢谢弗雷德里克。我运行了 nghttp 并发现了一些有趣的结果。我用这些观察更新了这个话题。但是:现在我不确定是什么导致了这种差异!

标签: nginx haproxy http2 proxy-protocol


【解决方案1】:

Chrome 似乎确保如果在与通过 https 方案提供的请求相对应的流上发送推送,则承诺也使用相同的方案:https://chromium.googlesource.com/chromium/src/+/master/net/spdy/chromium/spdy_session.cc#1766

我不确定检查是否正确:RFC 7540 说发送PUSH_PROMISE 的服务器应该是权威的。对于http,这意味着主机名匹配,因此浏览器应该能够处理该文件。

也就是说,即使浏览器接受了推送,它也只会在浏览器发出针对http://127.0.0.1:8002/image.jpg 的请求时才使用它。如果 HTML 是通过https 获得的,并且它请求了/image.jpg,那么我不确定浏览器是否会接受获取http://127.0.0.1:8002/image.jpg

这将我们带到 nginx 将方案设置为http。我认为这是由于 haproxy 终止 SSL 的事实,因此 ngnix 看到传入的明文连接,并且就它而言,该方案 http。我对 ngnix 的了解还不够,无法建议解决此问题。

【讨论】:

  • 你似乎很准。我记录了 nginX' $scheme 变量,它始终设置为 http。两者都用于 http/1.1 作为 http/2 流量!但是,我找不到类似的案例或解决方法:(。
  • 如果使用另一台服务器是一个选项,H2O 没有这个问题:github.com/h2o/h2o/blob/master/lib/http2/connection.c#L1484 它从原始流中复制方案,正如预期的那样。
  • 刚刚测试了 Apache,它同样适用于此(即它从原始请求复制方案)。此外,鉴于浏览器不支持 HTTP/2 over HTTP,我不确定浏览器是否会将纯文本 HTTP/2 推送资源视为权威?
  • 我不能说浏览器将永远支持它,但我们努力定义在 TLS HTTP/2 连接上使用 http 方案:tools.ietf.org/html/rfc8164#section-2 -- 请注意该方案和TLS 的使用是两件不同的事情。因此,理论上,您可以通过 TLS 连接使用和http 方案。
  • 我在他们的问题跟踪器上打开了一个问题:trac.nginx.org/nginx/ticket/1549#ticket
【解决方案2】:

我最终在 NginX 跟踪器上打开了一张票。它得到了修复。该修复程序在最近发布的 1.15.1 版本中可用。

修正:如果 SSL 被 nginx 前面的代理服务器终止,则 HTTP/2 服务器推送不起作用。

感谢您的帮助!

【讨论】:

    猜你喜欢
    • 2014-02-06
    • 1970-01-01
    • 2021-04-28
    • 2016-11-12
    • 2020-04-05
    • 1970-01-01
    • 1970-01-01
    • 2021-12-27
    • 2012-09-07
    相关资源
    最近更新 更多