apache 从虚拟主机的 URL 中删除 Tomcat 上下文(mod_jk、mod_rewrite)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2063895/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Removing Tomcat context from URLs for a virtual host (mod_jk, mod_rewrite)
提问by Richard H
I have a single Tomcat instance containing a number of webapps, each accessible via it's /Context. Tomcat is behind httpd (actually Debian Apache2), configured with virtual hosts to serve each app/Context. Tomcat connectivity is with mod_jk.
我有一个包含多个 webapps 的 Tomcat 实例,每个都可以通过它的 /Context 访问。Tomcat 位于 httpd(实际上是 Debian Apache2)之后,配置了虚拟主机来为每个应用程序/上下文提供服务。Tomcat 连接使用 mod_jk。
This works fine when I don't care about removing the context from urls: when the root of a virtual domain is requested, the requested is redirected to domain.com/Context.
当我不关心从 url 中删除上下文时,这很好用:当请求虚拟域的根时,请求被重定向到 domain.com/Context。
However for one app I dowant to remove the context. I believe this can be done by using mod_rewrite, and passing the re-written url to mod_jk for passing on to the correct Tomcat context. So my Debian Apache2 sites-available file looks like this:
但是,对于一个应用程序,我确实想删除上下文。我相信这可以通过使用 mod_rewrite 来完成,并将重写的 url 传递给 mod_jk 以传递到正确的 Tomcat 上下文。所以我的 Debian Apache2 站点可用文件如下所示:
NameVirtualHost *
<VirtualHost *>
ServerName domain.be
DocumentRoot /home/webapp/app/static/domain/
RewriteEngine on
RewriteRule ^/(.*)$ /Context/ [L,PT]
RewriteLog "/var/log/apache2/domain-rewrite.log"
RewriteLogLevel 4
JkLogFile /var/log/apache2/domain-mod_jk.log
JkLogLevel debug
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
JkMount /Context w1
JKMount /Context* w1
JkOptions +ForwardURICompat
ErrorLog /var/log/apache2/domain_error.log
CustomLog /var/log/apache2/domain_access.log combined
LogLevel warn
</VirtualHost>
According to the docs, the [PT] flag and +ForwardURICompat options should result in the rewritten URL being passed to jk_mod. However that doesn't seem to be happening.
根据文档,[PT] 标志和 +ForwardURICompat 选项应该导致重写的 URL 被传递给 jk_mod。然而,这似乎并没有发生。
The URL is being re-written, but it seems as if mod_jk is ignoring it: A request for domain.be/Context for example gets rewritten as /Context/Context - but is still handed to mod_jk as /Context.
URL 正在被重写,但似乎 mod_jk 忽略了它:例如,对 domain.be/Context 的请求被重写为 /Context/Context - 但仍然作为 /Context 传递给 mod_jk。
Any ideas? Incidentally, I cannot use mod_proxy at the moment.
有任何想法吗?顺便说一句,我目前无法使用 mod_proxy。
Thanks
谢谢
回答by Nestor Urquiza
@Josh, I think this solution won't work if tomcat performs any redirects. This is the typical case for example in an application demanding a login. When the user is not authenticated the app will redirect to something like /login however tomcat will append the current context like in /context/login so at the end the context does show in the URL.
@Josh,我认为如果 tomcat 执行任何重定向,此解决方案将不起作用。这是典型的情况,例如在要求登录的应用程序中。当用户未通过身份验证时,应用程序将重定向到 /login 之类的内容,但是 tomcat 会像 /context/login 一样附加当前上下文,因此最后上下文确实显示在 URL 中。
As you mentioned in your other question/response using just mod-jk plus tomcat virtual hosts is an option but there you will need to deploy your applications as ROOT.war which might not be that straightforward. There is a workaround so your application can be just dropped into tomcat webapps folder but as I described herethe server will deploy the app at least twice.
正如您在其他问题/回复中提到的,仅使用 mod-jk 和 tomcat 虚拟主机是一种选择,但您需要将应用程序部署为 ROOT.war,这可能不是那么简单。有一种解决方法,因此您的应用程序可以直接放入 tomcat webapps 文件夹中,但正如我在此处所述,服务器将至少部署应用程序两次。
It would be great if RewriteRule[P] plus JkOptions +ForwardURICompat could work but it doesn't. BTW I have tested this and I know mod_proxy does work as I proxied my site to cnn.com and I got their page under my site URL. Below are the logs BTW for the requests where you can see a proxy is being used:
如果 RewriteRule[P] 加上 JkOptions +ForwardURICompat 可以工作但它没有,那就太好了。顺便说一句,我已经测试过了,我知道 mod_proxy 确实可以工作,因为我将我的网站代理到 cnn.com 并且我在我的网站 URL 下找到了他们的页面。以下是请求的日志 BTW,您可以在其中看到正在使用代理:
127.0.0.1 - - [15/Dec/2011:12:56:34 --0500] [localhost/sid#1008ef278][rid#1009980a8/initial] (2) forcing proxy-throughput with http://localhost/nestorurquiza-app/
127.0.0.1 - - [15/Dec/2011:12:56:34 --0500] [localhost/sid#1008ef278][rid#1009980a8/initial] (1) go-ahead with proxy request proxy:http://localhost/nestorurquiza-app/ [OK]
127.0.0.1 - - [15/Dec/2011:12:56:49 --0500] [localhost/sid#1008ef278][rid#1009aaca8/initial] (2) forcing proxy-throughput with http://localhost/nestorurquiza-app/login
127.0.0.1 - - [15/Dec/2011:12:56:49 --0500] [localhost/sid#1008ef278][rid#1009aaca8/initial] (1) go-ahead with proxy request proxy:http://localhost/nestorurquiza-app/login [OK]
127.0.0.1 - - [15/Dec/2011:12:57:15 --0500] [localhost/sid#1008ef278][rid#1009980a8/initial] (2) forcing proxy-throughput with http://localhost/nestorurquiza-app/j_spring_security_check
127.0.0.1 - - [15/Dec/2011:12:57:15 --0500] [localhost/sid#1008ef278][rid#1009980a8/initial] (1) go-ahead with proxy request proxy:http://localhost/nestorurquiza-app/j_spring_security_check [OK]
127.0.0.1 - - [15/Dec/2011:13:08:41 --0500] [localhost/sid#1008ef278][rid#1009980a8/initial] (2) forcing proxy-throughput with http://localhost/nestorurquiza-app/
127.0.0.1 - - [15/Dec/2011:13:08:41 --0500] [localhost/sid#1008ef278][rid#1009980a8/initial] (1) go-ahead with proxy request proxy:http://localhost/nestorurquiza-app/ [OK]
回答by Josh Johnson
I'll leave my original answer up but it is wrong. The proper way to do this would be with a Tomcat VirtualHost:
我会保留我原来的答案,但这是错误的。正确的方法是使用 Tomcat VirtualHost:
http://tomcat.apache.org/tomcat-6.0-doc/virtual-hosting-howto.html
http://tomcat.apache.org/tomcat-6.0-doc/virtual-hosting-howto.html
The official walk-through in the link above is exactly what I've used several times now. I won't attempt to boil it down here.
上面链接中的官方演练正是我现在多次使用的。我不会试图在这里把它煮沸。
The concept is the same as an Apache Vhost. Create a virtual host (eg. for something.yourtdomain.com) and deploy your webapp to the ROOTapplication (/) for that vhost and you're all set. This way, if you already have a ROOTwebapp, you can have another at a different domain and the prior will remain unaffected.
该概念与 Apache Vhost 相同。创建一个虚拟主机(例如 for something.yourtdomain.com)并将您的 webROOT应用程序部署到该虚拟主机的应用程序 ( /) 中,然后您就大功告成了。这样,如果您已经拥有一个ROOTweb 应用程序,您可以在不同的域中拥有另一个,而先前的应用程序将不受影响。
As Nestor mentioned, an Apache rewrite rule will not handle things like tag libs and frameworks that automatically create links/form actions/etc for you based on the context root. In this case they will create the correct context root (/).
正如 Nestor 所提到的,Apache 重写规则不会处理诸如标签库和框架之类的事情,这些框架会根据上下文根自动为您创建链接/表单操作/等。在这种情况下,他们将创建正确的上下文根 ( /)。
回答by Josh Johnson
I've been using this with great success:
我一直在使用它并取得了巨大的成功:
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/(Context/.*)$
RewriteRule ^/(.*)$ /Context/ [P,L]
Notes on your situation:
关于你的情况的注意事项:
- You will need to get mod_proxy working or the
[P]will be ignored and the request will be forwarded instead of proxied. There is no way around this. +ForwardURICompatis part of mod_jk and will take effect after the rewriting.- mod_jk is ignoring the request because it never gets there. You need a
RewriteCond(above) to prevent requests to /Context from being rewritten.
- 您需要让 mod_proxy 工作,否则
[P]将被忽略并且请求将被转发而不是代理。没有办法解决这个问题。 +ForwardURICompat是 mod_jk 的一部分,重写后生效。- mod_jk 忽略请求,因为它永远不会到达那里。您需要一个
RewriteCond(以上)来防止对 /Context 的请求被重写。
I'm currently looking for a way to do this without mod_rewrite and using, instead, just mod_jk and Tomcat <Host>'s. But I'm having trouble with apache, mod_jk and Tomcat hosts playing nicely together. The above should work fine for you.
我目前正在寻找一种无需 mod_rewrite 而是使用mod_jk 和 Tomcat <Host>'s的方法来做到这一点。但是我在使用 apache、mod_jk 和 Tomcat 主机时遇到了麻烦。以上应该适合你。
回答by simonarame
Following hints given by Nestor Urquiza's answer, i managed to solve the issue by defining additional Host in tomcat's server.xml because as said, the j_security_check request is answered by tomcat with a forward instruction to the browser which inevitably contains the context name so that users trying to login gets 408 errors. Therefore, a real passthrough inside Apache VirtualHost JkMount /* worker1directive is achievable by making the intended context, a ROOTone.
按照 Nestor Urquiza 的回答给出的提示,我设法通过在 tomcat 的 server.xml 中定义额外的 Host 来解决这个问题,因为如上所述,j_security_check 请求由 tomcat 用转发指令回答到浏览器,浏览器不可避免地包含上下文名称,以便用户尝试登录时出现 408 错误。因此,JkMount /* worker1通过使预期的上下文成为ROOT一个上下文,可以在 Apache VirtualHost指令中实现真正的传递。
The Apache httpd.conf [ and/or an included *.conf ] file :
Apache httpd.conf [和/或包含的 *.conf ] 文件:
<!-- the subdomain -->
<VirtualHost *:80>
ServerName appWelcome.example.org
ServerAlias www.appWelcome.example.org
JKMount /* worker1
</VirtualHost>
<!-- with mod_jk set up -->
LoadModule jk_module modules/mod_jk.so
JWorkersFile /etc/apache2/workers.properties
JkShmFile /var/log/apache2/mod_jk.shm
So to map all request made to subdomain http://appWelcome.example.org/directly to the in-charge /appWelcome tomcat context, the appWelcome context must be addressable with request to http://appWelcome.example.org:8080/
因此,要将向子域发出的所有请求http://appWelcome.example.org/直接映射到负责的 /appWelcome tomcat 上下文,appWelcome 上下文必须可通过请求寻址http://appWelcome.example.org:8080/
So the tomcat server.xml file would then wear a separate Hostfor the app you are wiling to expose: .
因此,tomcat server.xml 文件将为Host您希望公开的应用程序提供一个单独的文件: .
<Server ...>
<Service>
<Engine defaultHost="localhost" ...>
<Host name="appWelcome.example.org" appBase="appWelcomeBase" ... >
<Valve ... />
</Host>
<Host name="localhost" appBase="webapps" ...>
<!-- this Host is typically shipped with manager, host-manager, docs,
sample, examples and a default ROOT context that shows tomcat default home. -->
<Valve ... />
</Host>
</Engine>
</Service>
</Server>
Note that the permissions ( and selinux context if enabled ) have to be adjust to mimic the default Hostones as follows :
请注意,必须调整权限(如果启用了 selinux 上下文)以模仿默认权限Host,如下所示:
$CATALINA_HOME/conf/Catalina/app.example.orgas $CATALINA_HOME/conf/Catalina/localhost
$CATALINA_HOME/conf/Catalina/app.example.org作为 $CATALINA_HOME/conf/Catalina/localhost
$CATALINA_HOME/appWelcomeBaseas $CATALINA_HOME/webapps
$CATALINA_HOME/appWelcomeBase作为 $CATALINA_HOME/webapps
Whence this is done all that is left to do is issue rename and move the appWelcome.warweb archive for it to auto-deploy in the created appBase( replacing $CATALINA_HOME with its value, e.g. /var/www/tomcat7) :
完成此操作后,剩下要做的就是重命名并移动appWelcome.warWeb 存档以使其自动部署到已创建的appBase(将 $CATALINA_HOME 替换为其值,例如 /var/www/tomcat7):
# mv $CATALINA_HOME/webapps/appWelcome.war $CATALINA_HOME/appWelcomeBase/ROOT.war
Voila !
瞧!
回答by Kamran
Use mod_proxy_ajp instead mod_jk like below:
使用 mod_proxy_ajp 代替 mod_jk,如下所示:
<VirtualHost *:80>
ServerName domain.be
DocumentRoot /home/webapp/app/static/domain/
...
ProxyPass /Context ajp://localhost:8009/Context
ProxyPass / ajp://localhost:8009/Context/
...
</VirtualHost>

