在 Apache 2 代理 (mod_proxy) 后面的 Tomcat Web 应用程序中发送重定向
Posted
技术标签:
【中文标题】在 Apache 2 代理 (mod_proxy) 后面的 Tomcat Web 应用程序中发送重定向【英文标题】:Sending redirect in Tomcat web application behind a Apache 2 proxy (mod_proxy) 【发布时间】:2013-08-22 09:33:13 【问题描述】:我在 tomcat 上有一个 web 应用程序 http://localhost:8080/WebApp/
我已经配置了 Apache 2 (mod_proy),以便 localhost 可以直接访问 Web 应用程序,无需端口和名称:例如 http://localhost
<VirtualHost localhost:80>
ProxyPreserveHost On
ProxyPass / http://localhost:8080/WebApp/
ProxyPassReverse / http://localhost:8080/WebApp/
</VirtualHost>
http://localhost
上正确显示了 index.html。
但是如果一个 servlet 重定向:
@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
?
【问题讨论】:
您需要以 root 身份部署您的应用程序。我在下面添加了操作方法。 【参考方案1】:我在尝试将 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's 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 webmaster@localhost
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 上运行您的应用程序服务器
【讨论】:
【参考方案2】:感谢 Stuart 和他指向此博客的链接,我找到了解决方案: Reverse Proxying Tomcat Web Applications Behind 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
的内容重定向到开头没有/WebApp
的URL。
唯一的缺点是您的 Web 应用程序中不能有任何名为 WebApp
的子文件夹
【讨论】:
【参考方案3】:我也遇到了这个问题,花了一些时间。我相信,如果您将 apache httpd 配置更改为以下内容,您的重定向将起作用:
<VirtualHost localhost:80>
ProxyPreserveHost On
ProxyPass / http://localhost:8080/WebApp/
ProxyPassReverse / http://localhost/WebApp/
ProxyPassReverseCookiePath /WebApp /
</VirtualHost>
这是因为 ProxyPreserveHost 已打开,因此 tomcat 响应标头将包含代理标头(即 Location 标头是 http://localhost/WebApp
而不是 http://localhost:8080/WebApp
)。
作为脚注:这也适用于您想要更改您的 webapps 上下文。假设您想将公开可见的上下文更改为可以使用以下内容的上下文:
<VirtualHost localhost:80>
ProxyPreserveHost On
ProxyPass /context/ http://localhost:8080/WebApp/
ProxyPassReverse /context/ http://localhost/WebApp/
ProxyPassReverseCookiePath /WebApp /context
</VirtualHost>
作为参考,我发现这篇博文非常有帮助:Reverse Proxying Tomcat Web Applications Behind Apache
【讨论】:
谢谢,但这并没有解决问题。但是博客文章的链接非常有帮助。查看我更新的解决方案。 嗨@Mahe,很高兴这可以帮助您找到解决方案。我认为这是作为反向代理的 ProxyPassReverse 和 ProxyPreserveHost 指令的 apache httpd 在线文档中缺少的部分。 Apache httpd 通常用作反向代理,它充当反向代理的 Web 应用程序通常不在同一台服务器上。我能找到的所有示例都假设代理和代理机器在同一台机器上运行。对于其他查看这篇文章的人,请参阅apache httpd as reverse proxy 的文档 感谢您提供关于更改 webapp 上下文的脚注。真的很有帮助【参考方案4】:使用转发而不是重定向
我认为您的问题是使用 sendRedirect。调用 sendRedirect 实际上是假设向浏览器显示 URL 已被重定向。如果你想隐藏你需要使用转发。在你的 servlet 中试试这个而不是 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 );
在您的 context.xml 中设置 crossContext = "true",以便您可以将请求转发到其他 Web 应用程序。
<Context crossContext="true" ....../>
【讨论】:
嗯,真可惜...我计划让几个子域指向不同的网络应用程序。所以 ROOT 上下文不是一个选项。 我不明白你说的几个子域是什么意思。你的意思是例如/login1
重定向到/a.html
,/login2
重定向到/b.html
,/login3
重定向到/c.html
都被同一个servlet重定向?
不是我描述的问题,只是一个子问题。我有一个带有多个应用程序的 Tomcat 服务器。我现在想在我的服务器上将app1.domain.net
指向localhost:8080/app1/
和app2.domain.net
指向localhost:8080/app2
。我更喜欢子域,因为这样可以更轻松地稍后在多个服务器上分发应用程序(如果需要)
我明白了。试试我刚刚添加的新方法。如果您使用转发而不是重定向,则浏览器将无法获取新 URL。它将保持/app1
和/app1/app1.html
将保持隐藏状态。
Tomcat 的可能性很大。我以前不知道!但这并不真正适用于我的问题...【参考方案5】:
您已经使用 AJP Connector 来连接 apache2 和 tomcat ,这将是完美的解决方案。
如果你需要如何配置这个,告诉我,我会解释这个细节
【讨论】:
ProxyPreserveHost On ProxyPass / ajp://localhost:8009/MobikatWebApp/ ProxyPassReverse / ajp://localhost:8009/MobikatWebApp/
仍然是同样的问题...以上是关于在 Apache 2 代理 (mod_proxy) 后面的 Tomcat Web 应用程序中发送重定向的主要内容,如果未能解决你的问题,请参考以下文章