Использование http2_push с nginX в сочетании с HAProxy не работает

Я не могу заставить работать HTTP/2 push, когда nginX настроен за HaProxy. Однако он работает, когда nginX попадает прямо в веб-браузер.

Провел много исследований уже, но не нашел никаких намеков. Надеюсь, кто-нибудь знает, что я делаю не так. Смотрите конфигурацию и дальнейшие наблюдения ниже.

конфигурация

Соответствующая конфигурация HaProxy (версия 1.8.7) определяется следующим образом:

    имя внешнего интерфейса
        bind *:443 ssl crt certificate.pem alpn h2,http/1.1
        режим tcp
        use_backend app-http2 if { ssl_fc_alpn -i h2 }
        приложение default_backend

    backend app-http2
        режим tcp
        сервер lamp2 127.0.0.1:8002 проверьте send-proxy

И соответствующая конфигурация nginX (версия 1.14.0) выглядит следующим образом:

    http {
        # Это тот, который я хотел бы использовать
        сервер {
            прослушать 8002 http2 proxy_protocol;

            название сервера _;
            root         /usr/share/nginx/html;

            место нахождения / {
                http2_push /image.jpg;
            }
        }

        # К этому можно получить доступ напрямую; и * работает *
        сервер {
            прослушать 8004 http2 ssl;

            сертификат ssl_certificate;
            ssl_certificate_key private.key;

            название сервера _;
            root         /usr/share/nginx/html;

            место нахождения / {
                http2_push /image.jpg;
            }
        }
    }

наблюдения

  • В журналах nginx я могу убедиться, что оба способа доступа к контенту используют HTTP2.
  • Когда я использую Chrome для доступа к странице, я вижу, что push используется только при прямом посещении nginX

Обновление 9 мая 2018 года до сих пор не решено. Но люди, похоже, согласны с тем, что это ошибка. Я открыл проблему на их трекере: https://trac.nginx.org/nginx/ticket/1549

Обновление 26 апреля 2018

Кажется, проблема больше, чем просто http2 push. Если я войду $scheme Переменная nginX всегда установлена ​​в http, Оба при доступе с http как с http2.

Так что это, очевидно, похоже на проблему. Однако я не уверен, как я могу это исправить. Haproxy работает в режиме TCP; таким образом, вероятно, не будет делать ничего плохого.

Связанная (но, возможно, устаревшая) тема переполнения стека - это переменная схемы nginx $, стоящая за балансировщиком нагрузки. Но этот ответ не поможет решить эту проблему!

Обновление 25 апреля 2018

До сих пор не работает. Но на шаг ближе. Запустил nghttp2 на обоих, и результаты найдены ниже.

Похоже, что оба имеют встроенный ресурс /image.jpg. Но тот, который проходит через haproxy, имеет схему, установленную на http; а не в https. Как можно увидеть в этом diff:

diff запросов nghttp

Я предполагаю из-за этого; Chrome не будет использовать этот отправленный ресурс. Я, однако, не уверен, что вызывает это!

У кого-нибудь есть ключ?


Полный вывод обеих команд:

    nghttp -nv https://127.0.0.1:8004/ [0,001] Подключено Согласованный протокол: h2 [0,003] отправить фрейм SETTINGS (niv=2)
    [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
    [SETTINGS_INITIAL_WINDOW_SIZE(030): 0x04) 0,003] отправить кадр PRIORITY (dep_stream_id=0, вес =201, эксклюзив = 0) [0,003] отправить кадр PRIORITY (dep_stream_id=0, вес =101, эксклюзив = 0) [0,003] отправить кадр PRIORITY (dep_stream_id=0, вес =1, эксклюзив = 0) [0,003] отправить кадр PRIORITY (dep_stream_id=7, вес =1, эксклюзив = 0) [0,003] отправить кадр PRIORITY (dep_stream_id=3, вес =1, эксклюзив = 0) [0,003] отправить кадр HEADERS; END_STREAM | END_HEADERS | ПРИОРИТЕТ (padlen=0, dep_stream_id=11, вес =16, эксклюзив =0); Открыть новый поток: метод: GET: путь: /: схема: https: полномочия: 127.0.0.1:8004 принять: */* принять кодировку: gzip, удалить пользовательский агент: nghttp2/1.25.0
    [  0,003] recv SETTINGS frame 
    (niv=3)
    [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):128]
    [SETTINGS_INITIAL_WINDOW_SIZE(0x04):65536]
    [SETTINGS_MAX_FRAME_SIZE(0x05):16777215]
    [  0,003], кадр: 211, резервное копирование_обозначения_обозначения_обозначения: 0,001], кадр: 181, резервное копирование_обозначения_обозначения_данных_данных_2_данных_данных_данных_2_данных_данных_2_данных_данных_данных_обозначения_для_данных_2_данных_данных_2_данных_данных_2_данных_2_данных_2_данных_2_данных_данных_данных_данных_данных_2_данных_2_данных_2_данных_2_данных_2_данных_2_2_2. ACK (niv = 0) [0,003] recv SETTINGS frame; ACK
    (niv=0)
    [  0.003] recv (stream_id = 13): метод: GET [0.003] recv (stream_id = 13): путь: /image.jpg
    [  0.003] recv (stream_id=13): схема: https [0.003 ] recv (stream_id = 13): права доступа: 127.0.0.1:8004
    [  0.003] recv (stream_id=13) accept-encoding: gzip, deflate
    [  0.003] recv (stream_id=13) user-agent: nghttp2/1.25.0
    [  0,003] recv PUSH_PROMISE frame; END_HEADERS
    (padlen=0, обещанный_поток = 2) [0,003] recv (stream_id = 13): статус: 200 [0.003] recv (stream_id = 13) сервер: nginx/1.14.0
    [  0.003] recv (stream_id=13) дата: Ср, 25 апреля 2018 15:08:26 GMT
    [  0.003] recv (stream_id=13) тип контента: text/html
    [  0.003] recv (stream_id=13) content-length: 638
    [  0.003] recv (stream_id=13) Последнее изменение: Ср, 25 апреля 2018 11:42:58 GMT
    [  0.003] recv (stream_id=13) etag: "5ae069c2-27e"
    [  0.003] recv (stream_id=13) accept-range: bytes
    [  0.003] recv HEADERS Рамка; END_HEADERS
    (padlen=0); Заголовок первого ответа [  0.004] recv DATA frame; 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) дата: ср, 25 апр. 2018 15:08:26 GMT
    [  0.004] recv (stream_id=2) content-type: image/jpeg
    [  0.004] recv (stream_id=2) content-length: 182884
    [  0.004] recv (stream_id=2) последнее изменение: сб, 18 июн 2016 15:42:26 GMT
    [  0.004] recv (stream_id=2) etag: "57656be2-2ca64"
    [  0.004] recv (stream_id=2) accept-range: bytes
    [  0.004] recv HEADERS frame; END_HEADERS
    (padlen=0); Заголовок ответа первого нажатия [0,004] recv DATA frame [0.004] recv DATA frame [0.004] recv DATA frame [0.004] recv DATA frame [0.004] recv DATA frame [0.004] отправить WINDOW_UPDATE кадр (window_size_increment=33248)
    [  0.004] отправить WINDOW_UPDATE frame 
    (window_size_increment=32768)
    [  0.004] recv DATA frame 
    [  0.004] recv DATA frame 
    [  0.004] recv DATA frame 
    [  0.046] recv DATA frame 
    [  0.046] recv DATA frame 
    [  0.046] recv DATA frame 
    [  0.046] recv DATA frame 
    [  0.046] recv DATA frame 
    [  0.046] отправка WINDOW_UPDATE frame 
    (window_size_increment=32925)
    [  0.046] send WINDOW_UPDATE frame 
    (window_size_increment=32767)
    [  0.046] recv DATA frame 
    [  0.046] отправка WINDOW_UPDATE frame 
    (window_size_increment=32768)
    [  0.046D] [0.068] [ window_size_increment=32768)
    [  0.046] recv DATA frame 
    [  0.090] recv DATA frame 
    [  0.090] recv DATA frame 
    [  0.090] recv DATA frame 
    [  0.090] recv DATA frame 
    [  0.090] recv DATA frame 
    [  0.090] recv DATA frame 
    [  0.090] recv Кадр DATA [0.090] отправляет кадр WINDOW_UPDATE (ветер ow_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] recata DATA DATA 0.134] recv DATA frame; END_STREAM
    [  0,134] отправить кадр GOAWAY (last_stream_id=2, код ошибки =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); Открыть новый поток: метод: GET:дорожка: /: схема: https: орган: 127.0.0.1:8002
    принять: */*
    принять кодировку: gzip, deflate
    user-agent: nghttp2/1.25.0
    [  0.003] recv SETTINGS frame 
    (NIV =3)
    [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):128]
    [SETTINGS_INITIAL_WINDOW_SIZE(0x04):65536]
    [SETTINGS_MAX_FRAME_SIZE(0x05):16777215]
    [  0.003] recv WINDOW_UPDATE кадр 
    (Window_size_increment=2147418112)
    [  0.003] отправить кадр настроек; ACK
    (NIV = 0)
    [0.004] recv SETTINGS frame; ACK
    (NIV = 0)
    [0.004] recv (stream_id = 13): метод: GET
    [0.004] recv (stream_id = 13): путь: /image.jpg
    [  0.004] recv (stream_id=13): схема: http
    [0.004] recv (stream_id = 13): права доступа: 127.0.0.1:8002
    [  0.004] recv (stream_id=13) принять кодировку: gzip, deflate
    [  0.004] recv (stream_id=13) user-agent: nghttp2/1.25.0
    [  0.004] recv PUSH_PROMISE frame; END_HEADERS
    (padlen=0, обещанный_поток_ид = 2)
    [0.004] recv (stream_id = 13): статус: 200
    [0.004] сервер recv (stream_id = 13): nginx / 1.14.0
    [0.004] дата записи (stream_id = 13): среда, 25 апреля 2018 г. 15:08:45 по Гринвичу
    [0.004] recv (stream_id = 13) тип контента: текст /html
    [  0.004] recv (stream_id=13) content-length: 638
    [  0.004] recv (stream_id=13) последнее изменение: ср, 25 апр 2018 11:42:58 GMT
    [  0.004] recv (stream_id=13) etag: "5ae069c2-27e"
    [  0.004] recv (stream_id=13) accept-range: bytes
    [0.004] recv HEADERS frame; END_HEADERS
    (Padlen =0); Заголовок первого ответа
    [0.004] recv DATA frame; END_STREAM
    [0.004] recv (stream_id = 2): статус: 200
    [0.004] сервер recv (stream_id = 2): nginx / 1.14.0
    [0.004] дата записи (stream_id = 2): среда, 25 апреля 2018 15:08:45 по Гринвичу
    [0.004] recv (stream_id = 2) content-type: image / jpeg
    [0.004] recv (stream_id = 2) content-length: 182884
    [0.004] recv (stream_id = 2) последнее изменение: суббота, 18 июня 2016 15:42:26 GMT
    [0.004] recv (stream_id = 2) etag: "57656be2-2ca64"
    [0.004] recv (stream_id = 2) accept-range: bytes
    [0.004] recv HEADERS frame; END_HEADERS
    (Padlen =0); Заголовок ответа первого толчка
    [0.004] recv DATA frame 
    [0.004] recv DATA frame 
    [0.004] recv DATA frame 
    [0.004] recv DATA frame 
    [0.004] recv DATA frame 
    [0.004] отправить кадр WINDOW_UPDATE 
    (Window_size_increment=33406)
    [  0.004] отправить кадр WINDOW_UPDATE 
    (Window_size_increment=32768)
    [  0.004] recv DATA frame 
    [  0.004] recv DATA frame 
    [  0.004] recv DATA frame 
    [  0.044] recv DATA frame 
    [  0.044] отправить кадр WINDOW_UPDATE 
    (Window_size_increment=32767)
    [  0.044] отправить кадр WINDOW_UPDATE 
    (Window_size_increment=32767)
    [  0.044] recv DATA frame 
    [  0.044] recv DATA frame 
    [  0.045] recv DATA frame 
    [  0.045] recv DATA frame 
    [  0.045] отправить кадр WINDOW_UPDATE 
    (Window_size_increment=32768)
    [  0.045] отправить кадр WINDOW_UPDATE 
    (Window_size_increment=32768)
    [  0.045] recv DATA frame 
    [  0.045] recv DATA frame 
    [  0.045] recv DATA frame 
    [  0.045] recv DATA frame 
    [  0.045] отправить кадр WINDOW_UPDATE 
    (Window_size_increment=32767)
    [  0.045] отправить кадр WINDOW_UPDATE 
    (Window_size_increment=32767)
    [  0.045] recv DATA frame 
    [  0.046] recv DATA frame 
    [  0.046] recv DATA frame 
    [  0.046] recv DATA frame 
    [  0.046] отправить кадр WINDOW_UPDATE 
    (Window_size_increment = 32768)
    [0.046] отправить кадр WINDOW_UPDATE 
    (Window_size_increment=32768)
    [  0.046] recv DATA frame 
    [  0.046] recv DATA frame 
    [  0.046] recv DATA frame; END_STREAM
    [  0.046] отправить кадр GOAWAY 
    (last_stream_id=2, error_code=NO_ERROR(0x00), opaque_data(0)=[])

2 ответа

Решение

Я закончил тем, что открыл билет на трекере NginX. И это исправлено. Исправление доступно в недавно выпущенной версии 1.15.1.

Исправление: выдвижение HTTP/2-сервера не работало, если SSL был прерван прокси-сервером перед nginx.

Спасибо за помощь!

Похоже, что Chrome гарантирует, что если отправка push-сообщения в потоке, соответствующем запросу, обслуживаемому через 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, чтобы предложить решение для этого.

Другие вопросы по тегам