Отправка перенаправления в веб-приложении Tomcat за прокси-сервером Apache 2 (mod_proxy)
У меня есть веб-приложение на tomcat http://localhost:8080/WebApp/
Я сконфигурировал Apache 2 (mod_proy), чтобы веб-приложение было напрямую доступно локальным хостом с внешним портом и именем: например, http://localhost
<VirtualHost localhost:80>
ProxyPreserveHost On
ProxyPass / http://localhost:8080/WebApp/
ProxyPassReverse / http://localhost:8080/WebApp/
</VirtualHost>
Указатель index.html корректно отображается на http://localhost
.
Но если сервлет перенаправляет:
@WebServlet(description = "...", urlPatterns = { "/login" })
public class LoginServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws IOException
{
response.sendRedirect("a.html");
}
}
и я использую URL http://localhost/login
- меня перенаправляют на http://localhost/WebApp/a.html
Как мне получить правильное перенаправление на http://localhost/a.html
?
Ответы
Ответ 1
Благодаря Стюарту и его ссылке на этот блог я нашел решение:
Обратное проксирование веб-приложений Tomcat за Apache
Решение: ProxyPreserveHost необходимо отключить!
Причина. Если он включен, заголовки ответов, возвращаемые бэкэндом прокси, будут содержать "localhost" или реальный домен без номера порта (или 80). Таким образом, шаблон ProxyPassReverse не соответствует (из-за другого порта и если используется другое имя домена, также имя домена не будет соответствовать).
Конфигурация:
<VirtualHost localhost:80>
ProxyPreserveHost Off
ProxyPass / http://localhost:8080/WebApp/
ProxyPassReverse / http://localhost:8080/WebApp/
</VirtualHost>
Но это работает только через http, а не через ajp (я не знаю почему).
Если вы все еще хотите использовать ajp, вы можете использовать следующее обходное решение - пусть Apache сделает еще одно перенаправление после неправильного перенаправления:
<VirtualHost localhost:80>
ProxyPass /WebApp !
ProxyPass / ajp://localhost:8009/WebApp/
ProxyPassReverse / ajp://localhost:8009/WebApp/
RedirectMatch 301 ^/WebApp/(.*)$ /$1
RedirectMatch 301 ^/WebApp$ /
</VirtualHost>
Директива ProxyPass /WebApp !
необходима для исключения пути от дальнейшей обработки в mod_proxy (поскольку директивы прокси оцениваются перед директивами перенаправления)
Затем директивы RedirectMatch
перенаправляют все, указывая с /WebApp/...
соответственно /WebApp
на URL без /WebApp
в начале.
Единственный недостаток заключается в том, что у вас не должно быть подпапок с именем WebApp
в вашем веб-приложении
Ответ 2
У меня также была эта проблема и потратил на нее некоторое время. Я считаю, что если вы измените конфигурацию apache httpd на следующее, ваше перенаправление будет работать:
<VirtualHost localhost:80>
ProxyPreserveHost On
ProxyPass / http://localhost:8080/WebApp/
ProxyPassReverse / http://localhost/WebApp/
ProxyPassReverseCookiePath /WebApp /
</VirtualHost>
Это связано с тем, что заголовки ответов tomcat будут содержать заголовки прокси (т.е. заголовок Location http://localhost/WebApp
, а не http://localhost:8080/WebApp
), поскольку включен ProxyPreserveHost.
Как сноска: это также работает с вами, чтобы изменить ваш контекст webapps. Предположим, вы хотели изменить контекст, видимый на публике, в контекст, который вы можете использовать:
<VirtualHost localhost:80>
ProxyPreserveHost On
ProxyPass /context/ http://localhost:8080/WebApp/
ProxyPassReverse /context/ http://localhost/WebApp/
ProxyPassReverseCookiePath /WebApp /context
</VirtualHost>
Для справки я нашел этот пост в блоге чрезвычайно полезным: Обратное проксирование веб-приложений Tomcat за Apache
Ответ 3
вы используете AJP Connector для подключения apache2 и tomcat, это будет идеальное решение для этого.
если вам нужно как это настроить, скажите, что я объясню эту деталь
Ответ 4
Использовать переадресацию вместо перенаправления
Я думаю, что ваша проблема заключается в использовании sendRedirect. Вызов sendRedirect на самом деле предполагает показать браузеру, что URL-адрес перенаправлен. Если вы хотите скрыть, что вам нужно использовать переадресацию. В вашем сервлете попробуйте это вместо sendRedirect.
String servletPath = request.getServletPath();
if(servletPath.equals("/app1")){
ServletContext ctx = request.getServletContext().getContext("/app1");
RequestDispatcher dispatcher=ctx.getServletContext().getRequestDispatcher( "/app1/app1.html" ); // or wherever you actually keep app1.html
dispatcher.forward( request, response );
}
Внутри вашего контекстного .xml установите crossContext = "true", чтобы вы могли пересылать запросы другим веб-приложениям.
<Context crossContext="true" ....../>
Ответ 5
У меня была такая же проблема, когда я пытался перенаправить запрос apache2 (работающий на порт 80) на tomcat (сервер приложений, запущенный на порту 8080).
Это конфигурация, которая работает отлично.
Перейдите к /etc/apache2/sites-available/000-default.conf
и добавьте следующую конфигурацию:
<VirtualHost *:80>
# The ServerName directive sets the request scheme, hostname and port that
# the server uses to identify itself. This is used when creating
# redirection URLs. In the context of virtual hosts, the ServerName
# specifies what hostname must appear in the request Host: header to
# match this virtual host. For the default virtual host (this file) this
# value is not decisive as it is used as a last resort host regardless.
# However, you must set it for any further virtual host explicitly.
#ServerName www.example.com
# for redirecting the websocket requests
ProxyPass /ws ws://localhost:7681/
#ProxyPass /ws ws://localhost:7681/
ProxyPassReverse /ws ws://localhost:7681/
ServerAdmin [email protected]
DocumentRoot /var/www/html
# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
# error, crit, alert, emerg.
# It is also possible to configure the loglevel for particular
# modules, e.g.
#LogLevel info ssl:warn
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
# For most configuration files from conf-available/, which are
# enabled or disabled at a global level, it is possible to
# include a line for only one particular virtual host. For example the
# following line enables the CGI configuration for this host only
# after it has been globally disabled with "a2disconf".
#Include conf-available/serve-cgi-bin.conf
# for redirecting the http request
ProxyPass /applicationContextUrl ' http://localhost:8080/applicationContextUrl
ProxyPassReverse /applicationContextUrl http://localhost:8080/applicationContextUrl
ProxyPassReverseCookiePath /applicationContextUrl /
ProxyPassReverseCookieDomain localhost applicationContextUrl
ProxyRequests off
ProxyTimeout 15
ErrorLog ${APACHE_LOG_DIR}/nirad_error.log
LogLevel debug
CustomLog ${APACHE_LOG_DIR}/nirad_access.log combined
<Proxy *>
AddDefaultCharset off
Order deny,allow
Allow from all
#Require all denied
Require all granted
Require local
</Proxy>
</VirtualHost>
Готово.
Теперь перейдите в терминал и нажмите следующую команду.
-
sudo a2enmod proxy_http
(для перенаправления http).
-
sudo a2enmod proxy_wstunnel
(для перенаправления websocket)
- и
sudo service apache2 restart
- запустите сервер приложений на порту 8080