Apache 2.4.7 mod_proxy_wstunnel слишком много туннелирования (HTTP, а также WS)

Я запускаю Apache 2.4.7 в качестве обратного прокси на Ubuntu 14.04 LTS. Этот сервер Apache действует как точка входа для множества различных серверных приложений, доступ к которым осуществляется через различные конфигурации mod_proxy в блоках

. Мне нужно предоставить обратный прокси-доступ для приложения, использующего WebSockets. Это приложение Java Spring, которое обслуживает HTML и другие статические файлы через HTTP, а затем использует WebSocket для динамических данных после загрузки страницы.

У меня есть приложение, работающее за Nginx с использованием следующая конфигурация:

location /newapp/ {
    proxy_pass http://newapp.example.com:8080/;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

К сожалению, из-за необходимости модуля аутентификации Apache, который недоступен в Nginx, я не могу использовать его в производственной среде.

Я хочу сделать в псевдо-Apache-config:

<Location /newapp/>
    if not WebSockets:
        ProxyPass http://newapp.example.com:8080/
        ProxyPassReverse /
    else
        ProxyPass ws://newapp.example.com:8080/
        ProxyPassReverse /
</Location>

Модуль Apache mod_proxy_wstunnel заставляет меня думать, что это должно быть возможно. Доступ к WebSocket осуществляется по URL-адресу / api / socket / ... , поэтому я попытался разделить два типа ProxyPass , используя отдельные blocks:

<Location /newapp/>
    ProxyPass http://newapp.example.com:8080/ disablereuse=on
    ProxyPassReverse /

    ProxyPassReverseCookieDomain newapp.example.com apps.example.com
    ProxyPassReverseCookiePath http://newapp.example.com:8080/ /newapp/
</Location>

<Location /newapp/api/socket/>
    ProxyPass ws://newapp.example.com:8080/api/socket/
    ProxyPassReverse /
</Location>

Сначала это работает - браузер запрашивает http: //apps.example. com / newapp / , страница загружается через HTTP, статические ресурсы загружаются, код JavaScript подключается к веб-сокету, все в порядке.

Однако, когда новый запрос выполняется через HTTP - скажем, для GET /newapp/static/someimage.png, что-то пошло не так. Этот запрос не соответствует местоположению WebSocket, поэтому я ожидаю, что он будет прокси-сервером с GET /static/someimage.png до http://newapp.example.com:8080/ .

Вместо этого сервер приложений получает запрос на GET /newapp/static/someimage.png и возвращает 404, поскольку это не тот URL, о котором он знает. Это нарушает работу приложения, поскольку HTTP-запросы, которые должны работать, вместо этого завершаются ошибкой.

Примечания:

  • Это не работает. Это происходит только с изображениями - GET / newapp / api / ajax / someapicall также неправильно проксируется через прокси.
  • Это не всегда происходит. Во время тестирования, чтобы ответить на этот вопрос, мне удалось заставить приложение полностью работать. Это могло быть связано с временем - я оставил приложение запущенным, не взаимодействуя с ним в течение нескольких минут, прежде чем делать какие-либо новые HTTP-запросы. Когда я делал новые HTTP-запросы, они проходили правильно.
  • Отключение раздела приводит к двум вещам: WebSocket не может подключиться и HTTP запросы продолжают работать.
  • Я обнаружил эту проблему после обновления страницы с помощью кнопки «Обновить» в браузере. Вместо того, чтобы снова загружаться страница, я увидел экран приложения 404.

Я думаю, что происходит:

Я думаю, что mod_proxy_wstunnel , после активации первым запросом на соответствие / newapp / api / socket / , принимает на себя все последующие входящие запросы от клиента, независимо от того, соответствуют ли они Местоположение или нет. Я проверил это, добавив RequestHeader set Test "some_identifying_value" директиву к каждому Location - HTTP-запросам для статических файлов и для / api / socket / info заголовок Test на них, но неправильно проксированные HTTP-запросы не прошли тест Test заголовок на них, что говорит о том, что они передаются напрямую без обработки директивами Apache.

В конечном счете, мой вопрос таков: можно ли настроить любую версию Apache (я счастлив обновить!) до приложения на основе WebSocket с обратным прокси-сервером таким образом, чтобы HTTP-запросы также правильно проксировались через обратный прокси после подключения WebSocket? Если да, то как это настроено?

2
задан 9 March 2017 в 13:54
2 ответа

ответ Андерса дал мне 95% пути туда.

Основной сценарий:

  • У нас есть сервер на newapp.example.com
  • Порт 8080 работает как HTTP, так и WebSockets
  • URL, который отвечает на запросы WebSockets является /api/socket/
  • Мы обратно-проксируем это приложение, как http://apps.example. com/newapp/

Вот как настроить WebSockets и обратное проксирование HTTP для вышеописанного сценария в блоке :

<Location /newapp/>
    ProxyPass http://newapp.example.com:8080/
    ProxyPassReverse /

    RewriteEngine on
    RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
    RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
    RewriteRule /api/(.*) ws://newapp.example.com:8080/api/$1 [P]
</Location>

Окончательное правило перезаписи очень важно - без него мы передадим запрос /newapp/api/socket на WebSocket-сервер - который он отклонит.

Регекс разбирает все после api - возможно, есть лучший способ перехватить этот блок, но это сработало. Затем мы должны помнить, что нужно переадресовать /api/ на конечный URL редиректа.

Самое главное, что HTTP-запросы продолжают работать после установления соединения с WebSocket!

.
6
ответ дан 3 December 2019 в 08:52

Я использую apache 2.4 в качестве прокси-сервера перед моим приложением весенней загрузки, это приложение обслуживает некоторые звонки api, вебсокеты (sockjs) и некоторые статические страницы. У меня были некоторые проблемы с заставкой вебсокета работать, секрет был в том, чтобы добавить правила перезаписи , которые вы видите ниже, теперь это работает на меня, моя конфигурация виртуального хоста apache выглядит так:

<VirtualHost *:443>
  SSLEngine on
  SSLCertificateFile /etc/httpd/ssl/my.crt
  SSLCertificateKeyFile /etc/httpd/ssl/my.key
  SSLCertificateChainFile /etc/httpd/ssl/intermediate.crt
  ProxyPreserveHost On
  ProxyPass / http://127.0.0.1:8080/
  ProxyPassReverse / http://127.0.0.1:8080/
  ProxyRequests Off
  RewriteEngine on
  RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
  RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
  RewriteRule .* ws://localhost:6868%{REQUEST_URI} [P]
  ServerName my.dnsname.com
</VirtualHost>
2
ответ дан 3 December 2019 в 08:52

Теги

Похожие вопросы