Вопрос или проблема
У меня уже установлен Apache 2.4.19 на Ubuntu 16.04, который работает с Tomcat. Я пытаюсь добавить приложение на Node и перенаправить все запросы к /node на http://localhost:3000 с помощью ProxyPass. Моё приложение на Node, конечно же, слушает порт 3000.
Это очень хорошо работает для перенаправления моих запросов, таких как https://myapi.com/node/foo
Однако у меня есть проблемы с документацией, созданной с помощью apidoc, которую я отдаю статически в своём приложении на Node, используя app.use(express.static('doc'));
. Когда я перехожу по ссылке https://myapi.com/node, кажется, что все URLы такие как /vendor/xxx
, /locales/xxx
не получают префикс /node
. Я думал, что ProxyHTMLURLMap должен с этим справиться, но, похоже, я использую его неправильно.
Вот мой файл /etc/apache2/sites-enabled/000-default.conf (я убрал некоторые комментарии, чтобы сделать его короче)
<VirtualHost *:443>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
# Tomcat
JkMount /* worker1
# Конфигурация SSL
SSLEngine on
SSLCertificateFile /path/to/certificate
SSLCertificateKeyFile /path/to/private.key
SSLCACertificateFile /path/to/intermediate-cert
# Заголовки
Header always set Access-Control-Allow-Origin "*"
Header always set Access-Control-Allow-Headers "X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PULL"
# Возвращать 200 для всех запросов OPTIONS
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]
# Обратный прокси для Node
# Часть ниже должна была изменить относительный URL на /node/xxx, но, похоже, это не работает
ProxyHTMLURLMap http://localhost:3000 /node
<Location /node>
ProxyPass http://localhost:3000
ProxyPassReverse http://localhost:3000
ProxyHTMLEnable On
SetOutputFilter proxy-html
ProxyHTMLURLMap http://localhost:3000
</Location>
</VirtualHost>
<VirtualHost *:80>
ServerName myapi.com
Redirect / https://myapi.com/
</VirtualHost>
ИЗМЕНЕНИЕ
Я не могу использовать ProxyHTMLExtended On
по совету Эндрю Шульмана, потому что это испортит вывод apidoc.js
index.html
, сгенерированный с помощью apidoc.js, имеет это выражение в самом конце:
<script data-main="main.js" src="https://serverfault.com/questions/899237/vendor/require.min.js"></script>
Затем main.js
делает кучу require
Я пытался заменить main.js
на node/main.js
в выражении скрипта, но тогда требуют ошибки…
Я также заметил, что если я напрямую запрашиваю https://myapi/node/index.html, все файлы, похоже, загрузились нормально. Возможно, я просто сконфигурирую Apache для перенаправления /node на /node/index.html
По умолчанию модуль mod_proxy_html не переписывает ссылки в встроенном CSS и Javascript. Чтобы это включить, вам нужно установить ProxyHTMLExtended On
. Смотрите документацию.
Это может исправить вашу проблему, но это не затрагивает CSS и Javascript, которые загружаются из других файлов, а не включены встроенно. Если вы хотите попробовать исправить это тоже, вам нужно будет использовать другой модуль, такой как mod_sed или mod_line_edit. Это также может сработать для вас, но также может быть невозможно полностью исправить, так как в коде (т.е. Javascript) URL могут вычисляться произвольным образом, который регулярный парсер не может обнаружить.
Ответ или решение
Для решения вашей проблемы с перенаправлением запросов к Node.js приложению через Apache с использованием модуля mod_proxy_html
, давайте рассмотрим ряд подходов.
Шаг 1: Настройка конфигурации Apache
Ваше текущее содержимое файла /etc/apache2/sites-enabled/000-default.conf
можно немного изменить для правильной работы с ProxyHTMLURLMap
. Основная проблема в том, что модули mod_proxy
и mod_proxy_html
могут не обрабатывать URL в ваших статических файлах CSS и JS должным образом из-за того, что они не включаются в пересылку. Вот как можно настроить конфигурацию:
<VirtualHost *:443>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
# Tomcat
JkMount /* worker1
# SSL Config
SSLEngine on
SSLCertificateFile /path/to/certificate
SSLCertificateKeyFile /path/to/private.key
SSLCACertificateFile /path/to/intermediate-cert
# Headers
Header always set Access-Control-Allow-Origin "*"
Header always set Access-Control-Allow-Headers "X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PULL"
# Возвращение 200 для всех запросов OPTIONS
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]
# Обратный прокси к Node
<Location /node>
ProxyPass http://localhost:3000
ProxyPassReverse http://localhost:3000
ProxyHTMLEnable On
SetOutputFilter proxy-html
ProxyHTMLURLMap http://localhost:3000 /node
ProxyHTMLURLMap / /node # Добавить это правило
</Location>
</VirtualHost>
<VirtualHost *:80>
ServerName myapi.com
Redirect / https://myapi.com/
</VirtualHost>
Шаг 2: Использование ProxyHTMLExtended
Поскольку вы упомянули, что не можете использовать ProxyHTMLExtended On
, следует учитывать, что это может повлиять на корректность выводимого HTML. Однако, если это возможно сделать, попробуйте:
ProxyHTMLExtended On
Это позволит mod_proxy_html
также обрабатывать ссылки внутри CSS и JavaScript, что может помочь с вашими проблемами при запросах к статическим ресурсам.
Шаг 3: Решение проблемы с ссылками
Если у вас есть необходимость изменить ссылки в статических файлах, которые не обрабатываются модулем mod_proxy_html
, вы можете рассмотреть использование другого модуля Apache, такого как mod_sed
или mod_line_edit
. Эти модули могут редактировать содержимое страницы на лету, включая CSS и JavaScript файлы. Однако, стоит помнить, что такие решения могут быть сложными в настройке и не всегда гарантируют кросс-браузерную совместимость.
Шаг 4: Альтернативное решение
Если вы не можете заставить Apache правильно обрабатывать ссылки в статических файлах, то хорошей альтернативой было бы настроить в вашем Node.js приложении маршрутизацию. Например, вы можете создать отдельные маршруты в вашем Node.js приложении для обработки статических ресурсов, заменив их на /node/vendor/...
, /node/locales/...
.
app.use('/node/vendor', express.static('vendor'));
app.use('/node/locales', express.static('locales'));
Заключение
Комбинируя предложенные выше методы, вы сможете настроить ваш сервер Apache так, чтобы он корректно перенаправлял запросы к Node.js, а также обрабатывал статические файлы без специальных модификаций в их коде. Всегда тестируйте изменения на локальной машине, чтобы убедиться в их работоспособности, прежде чем применять на рабочем сервере.