先把问题说清楚,前端nginx占用81端口,由于80干了别的,暂时
location /app1/ {
indexindex.jsp index.html index.html index.shtml;
proxy_pass http://localhost:8080/app1/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ~ ^.+\.(png|jpg|jpeg|gif|ico|css|js|xml)$ {
root /home/gap/app/apache-tomcat-5.5.14/webapps;
}
上面的代码只是大略举例,个中处理静态内容的部分也可以用目录alias或者root的办法去处理,效果该当一样的,但是详细差异我也没深入理解, 不过这不是本日的重点。在这个配置下涌现的问题便是当访问http://host:81/app1/Login.do的时候,登录成功须要301跳转到用 户中央页面,然后跳转的地址本该当是http://host:81/app1/userindex.do,但是结果不太尽如人意,浏览器实际涌现的地址 http://host/app1/userindex.do。这里面的问题便是81端口没了,跑80端口去了,自然就404了。扯了一大段,这便是本日 想说的问题。
问题涌现了,自然得剖析缘故原由,由于我们这个项目中须要支持ssl,利用了Struts1.2的Framework,于是采取了SecurePlugIn(想理解的可以参照SSLExt Command 2.3节)的插件来处理。那么我首先疑惑是不是这个东西在作怪,看了下配置文件这个插件的enable都直接为false。看来不是这个插件作怪了,那么在不是运用本身逻辑在作怪的话那么可能是做事器配置有问题了,这个时候就该当直接从http要求开始剖析了。
首先我打开chrome,然后来剖析这次request发生了什么(打开开拓者工具中的Network面板),能创造的基本便是要求 Login.do是没问题的,但是Login.do之后发生的301重定向是缺点的,一个主要的线索便是Login.do的要求中response中的 Location的值是http://host/usercenter.do,这里丧失落了端口号。这个地方的详细缘故原由后边会提到,先说下办理思路。
办理思路可以有两个,第一个便是nginx是可以利用proxy_redirect来修正response的Location和Refresh的 值,Location自然可以被重新修正为81端口的地址,第二个便是找到是谁把Location搞错了,修正这个地方别搞错Location就行了。
办理思路1:利用nginx的proxy_redirect
这个思路实在有点侧重办理问题型,便是我看到这里错了,缘故原由不纠结,我让你好使就可以了。可能好多人都是这个思路,毕竟办理问题是紧张目的。
很多人在配置nginx的时候,习气参考官方wiki的Full Example (taken from Nginx site), 来做一些配置,参考这个肯定比参考baidu搜索出来的文档要靠谱很多,建议不理解每个属性的可以来参照下这个官方示例。这个配置里面 proxy_redirect的属性为off,很多人该当没有问过为什么就直接根据人家来做了,之以是这样下结论是由于我看到太多海内子的集成例子中都是 这样设置的了。我这里也是这样设置的,以前也倒是没想起来问下为啥,的确不太符合我的风格。反正做事器是这样配置的,现在是出来问题了,我们先来看下这个 属性能做什么。
首先看官方文档Reference:proxy_redirect的解释:
Sets a text that should be changed in the header fields “Location” and “Refresh” of a response from the proxied server. Suppose a proxied server returned the header field “Location: http://localhost:8000/two/some/uri/”.
基本意思便是修正代理做事器(也便是此时的nginx)的response的头信息里面的Location和Refresh的值,按照这个阐明的话我们的问题肯定就迎刃而解了,由于现在碰着的问题便是这个能够修正的两个中的一个Location出了问题,那么下面的代码就可以办理问题
proxy_redirect http://host http://host:81;
这样重启sudonginx -s reload然后再访问该当就ok了。实在你google搜索nginxproxy_redirect 重定向有好多这样的例子和这个办理办法是一样的,就不细说了,如果有人想理解的可以自己参照nginx官方文档和结合例子来操作下试试就可以理解了。
办理思路2:找到问题缘故原由,修正出错的地方办理
根据上个思路办理了问题往后,一点都没如释重负的觉得,反而各个地方都以为很空的觉得,由于有好几个疑问没办理,个中包括为啥是80而不是81或者8080没道理?这个Location是不是该当nginx来重写,修正掉那个跳转错的地方是不是比这个思路会更好?
那就先来剖析下问题的缘故原由:既然response的Locaiton不对,那么首先想到的便是这个Location是谁布局出来的,理解HTTP协 议的人该当都知道,request中的header都是client(浏览器等)布局好发送给做事器的,做事器收到要求往后布局response信息返回 给client。那么这样Location这个值肯定便是nginx或者Tomcat给搞出的问题了,这个地方nginx只是一个proxy server,那么response肯定是Tomcat发给nginx的,也便是说我们该当从Tomcat下手来剖析这个问题。
首先我就看了下Tomcat的官方文档 Proxy Support,这里面对这个先容如下:
The proxyName and proxyPort attributes can be used when Tomcat is run behind a proxy server. These attributes modify the values returned to web applications that call the request.getServerName() and request.getServerPort() methods, which are often used to construct absolute URLs for redirects. Without configuring these attributes, the values returned would reflect the server name and port on which the connection from the proxy server was received, rather than the server name and port to whom the client directed the original request.
意思便是proxyPort的属性便是用来我这种nginx做前端代理做事器Tomcat在后端处理动态要求的情形的。修正属性的值可以浸染于运用 的两个方法,紧张用于绝对路径和重定向之用。如果不配置的话,可能会不对头。那么既然是这里不对头,我就先把server.xml中我这个http的 connector(把稳是此处的connector是protocol="HTTP/1.1"的那个)的配置加入了proxyPort="81"(如果代理做事器域名和tomcat域名不一样,则需在设置proxyName的值,比如:nginx的域名为host,tomcat为localhost,则在connector的配置加入了proxyName="host"),重启Tomcat,然后把nginx上步骤的修正注释掉,重启测试。结果基本如所料,完备正常跳转了。
事情到了这个时候,实在问题基本明了了,不过我还是对这个Tomcat为啥默认解析了80端口很是迷惑。我下载了Tomcat的source来看下 问题究竟,看了往后用普通的措辞来表述的话便是这样:如果默认不配置proxyPort默认为0,然后在布局response的时候判断如果 proxyPort为0那么就不添加端口,不添加端口当然就默认走了80端口,源代码如下:
// FIXME: the code below doesnt belongs to here,
// this is only have sense
// in Http11, not in ajp13..
// At this point the Host header has been processed.
// Override if the proxyPort/proxyHost are set
String proxyName = connector.getProxyName();
intproxyPort = connector.getProxyPort();
if (proxyPort != 0) {
req.setServerPort(proxyPort);
}
if (proxyName != null) {
req.serverName().setString(proxyName);
}
到了这里就原形大白了,心里也没结了,一块石头终于落地了。