1

当在 HaProxy 后面配置 nginX 时,我无法让 HTTP/2 推送工作。但是,当 Web 浏览器直接点击 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 访问该页面时,我可以看到只有在直接访问 nginX 时才使用push

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

2018 年 4 月 26 日更新

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

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

一个相关(但可能已过时)的 Stack Overflow 主题是负载均衡器后面的 nginx $scheme 变量。但是那个答案无助于解决这个问题!

2018 年 4 月 25 日更新

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

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

nghttp 请求的差异

我假设因此;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)=[])

4

2 回答 2

0

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

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

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

这将我们带到 nginx 将方案设置为http. 我认为这是由于 haproxy 执行 SSL 终止,因此 ngnix 看到传入的明文连接,就它而言,该方案 http. 我对 ngnix 的了解还不够,无法建议对此进行修复。

于 2018-04-25T16:32:24.423 回答
0

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

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

谢谢您的帮助!

于 2018-07-05T08:03:23.790 回答