项目一直使用Nginx作为流量网关,由于网络调整,用户网络跟Nginx服务器网络无法直连,采用了端口映射的方式(服务实际地址为10.0.24.204/wywy,映射后为10.0.8.2:8000/wywy),导致nginx配置出现问题。
问题1: 根目录重定向错误
原NG配置中,设置了根目录 / 重定向到 /wywy。实现浏览器访问http://10.0.24.204
时,会自动跳转到http://10.0.24.204/wywy/
。原始配置如下:
server {
listen 80;
server_name localhost;
location / {
rewrite ^/$ /wywy/ permanent;
}
location ~ /wywy {
add_header Cache-Control "no-cache, no-store";
root /data/application;
index index.html index.htm;
}
}
但是当使用端口映射后,浏览器访问http://10.0.8.2:8000
,并没有跳转到http://10.0.8.2:8000/wywy
。NG返回301后,header里的Location为http://10.0.8.2/wywy
,注意端口消失了。
问题2: 资源目录重定向错误
不知你注意到没有,当浏览器访问http://10.0.24.204/wywy
地址后,会自动在后面加上斜杠/
,即变成http://10.0.24.204/wywy/
,打开开发者工具(F12),在network
标签里,会看到一个301和一个200,两次请求返回:
这是NG主动设置301 Moved Permanently的结果。原理是当用户输入了一个url地址,NG没有找到URL最后部分的资源,并且发现最后部分是一个文件目录(比如wywy是我的目录,里面只有一个index.html),则本次访问的状态码会被设置成301,并在Response header里增加一个Location项,下面会讲这个Location如何取值,这里默认返回的就是http://10.0.24.204/wywy/
,增加了一个斜杠/
。这时按照配置规则,在wywy/目录下查找index.html资源,于是返回了网页信息。
同样的,当使用端口映射以后,访问新地址http://10.0.8.2:8000/wywy
时,会被301重定向到http://10.0.8.2/wywy/
,增加斜杠/
但端口又消失了。
Nginx重定向配置
nginx默认有三个重定向的参数可以配置:
- absolute_redirect:On(开启)时使用绝对URL,并开启下面两个配置参数,共同影响301重定向时Location的取值。Off(关闭)时,使用相对URL作为Location取值。默认开启
- server_name_in_redirect:只在absolute_redirect开启时生效。On(开启)时,使用NG配置的server_name。Off(关闭)时,使用用户请求输入URL的服务器部分。默认关闭
- port_in_redirect:只在absolute_redirect开启时生效。On(开启)时,加入本地监听的的端口号,但是除443、80外。Off(关闭)时,不加端口号。默认开启
所以,在默认情况下,如果你的NG配置监听的是80或443这两个默认端口,则使用的是绝对URL+用户输入服务器host+无端口号。所以就出现了上面的端口消失情况。
解决方案
先重复下需要达到效果,使用端口映射10.0.8.2:8000 --> 10.0.24.204:80的情况下:
- 访问根目录
http://10.0.8.2:8000
可以自动跳转到http://10.0.8.2:8000/wywy/
- 访问资源目录没有带最后的斜杠
http://10.0.8.2:8000/wywy
,可以自动跳转到http://10.0.8.2:8000/wywy/
- 不影响原本ip访问
了解完原理后,解决方案就简单了:
-
直接在server中设置absolute_redirect参数为Off,这样NG就直接使用相对URL,即保留请求时的host和port,只修改uri部分,最终配置如下:
server { listen 80; server_name localhost; absolute_redirect off; location / { rewrite ^/$ /wywy/ permanent; } location ~ /wywy/ { add_header Cache-Control "no-cache, no-store"; root /data/application; index index.html index.htm; } }
该参数是一个全局参数,可能会影响其他规则的运作,造成不可知的问题影响其他服务。配置的时候应该考虑这个因素。
所以当你NG只提供你的一个服务时,可以放心采用1方案,快捷简单。
-
使用rewrite重写重定向路径,相当于自己定义重定向的规则,不受absolute_redirect配置影响。为了满足第二点需求,需要增加一个location项,最终配置如下:
server { listen 80; server_name localhost; #absolute_redirect on; # 默认为on location / { if (-d $request_filename) { rewrite ^/$ ${scheme}://${http_host}/wywy/ permanent; } } location /wywy { rewrite ^(.*)$ $scheme://${http_host}${uri}/ permanent; } location ~ /wywy/ { add_header Cache-Control "no-cache, no-store"; root /data/application; index index.html index.htm; } }
使用rewrite,手动指定用户访问根目录
/
以及/wywy
时,要如何跳转到/wywy/
。 -
(新增)无意中发现另外一个现象,网上找了圈资料,没有找到具体解释。使用rewrite重写,当跳转地址是以
/
开头时,nginx会默认使用绝对路径,并且受到absolute_redirect以及另外两个子参数的影响。此时rewrite时,会去替换整个URI。当把开头的斜杠/
去掉时,会默认使用相对路径,并且只会替换请求地址URI的最后一部分。下面讲rewrite会详细解释。所以实现上述需求跳转时,只要写明地址并不要以
/
开头即可。具体配置如下:server { listen 80; server_name localhost; #absolute_redirect on; # 默认为on location / { if (-d $request_filename) { rewrite ^/$ wywy/ permanent; } } location /wywy { rewrite ^(.*)$ wywy/ permanent; } location ~ /wywy/ { add_header Cache-Control "no-cache, no-store"; root /data/application; index index.html index.htm; } }
Rewrite使用以及参数解释
rewrite的功能就是,结合正则表达式,实现url重写重定向。他可以使用NG的全局变量和自定义变量。关键字位置为:server{}、location{}、if{}
语法: rewrite <regex> <replacement> [flag];
regex: 正则表达式
replacement:跳转后地址。可以写完整地址如http://www.baidu.com/somethings
,也可以省略前面的协议+host+port部分,如/wywy/
或者wywy/
。此时当以/
开头时,会默认按照规则补全协议、host、port(即绝对路径,并依赖上述absolute_redirect参数的控制),当不以/
开头时,会以相对路径进行跳转,注意这里相对的是当前资源的路径,如你访问http://10.0.24.204/abc/def/xyz
时,跳转路径会是http://10.0.24.204/abc/def/wywy/
flag:支持的flag标记,共4种last,break,redirect,permanent
四种flag标记
last:本条规则匹配完成后,继续向下匹配新的location URI规则,一般用在 server 和 if 中
break:本条规则匹配完成即终止,不再匹配后面的任何规则,一般使用在 location 中
redirect:返回302临时重定向,浏览器地址会显示跳转后的URL地址
permanent:返回301永久重定向,浏览器地址栏会显示跳转后的URL地址。
NGINX部分保留变量
$scheme: 协议部分,即http、tcp这些
$http_host: 服务器地址,包含端口号
$uri: 去掉协议、地址、端口后的资源相对路径,注意时自带最左边斜杠的。即/wywy
$request_filename: 请求的资源名称,即访问路径最后的部分。如http://10.0.8.2:8000/abc/wywy
则表示的是wywy
正则注意项
^
表示字符串开头
$
表示字符串结尾
[^abc]
如果在方括号里面则表示否定、非的意思。
案例解释
这里做一个实验,在nginx的根目录里做rewrite
server {
listen 80;
server_name localhost;
location / {
rewrite ^(.*)$ http://www.baidu.com permanent; # 1
rewrite ^(.*)$ ${scheme}://${http_host}${uri}wywy/ permanent; # 2
rewrite ^(.*)$ /wywy/ permanent; # 3
rewrite ^(.*)$ wywy/ permanent; # 4
rewrite ^/(.*)([^/]*)$ /wywy/ permanent; # 5
rewrite ^/(.*)([^/]*)$ wywy/ permanent; # 6
}
}
-
正则部分表示匹配所有,跳转地址是完整的百度首页。
访问
http://10.0.24.204/
,结果为:Location: http://www.baidu.com
,浏览器跳转到了百度。 -
正则部分表示匹配所有,跳转地址手动指定了用户访问的协议、地址端口、uri。
访问
http://10.0.24.204/
时,结果为:Location: http://10.0.24.204/wywy/
访问
http://10.0.24.204/abc
时,结果为:Location: http://10.0.24.204/abc/wywy/
访问
http://10.0.8.2:8000
时,结果为:Location: http://10.0.8.2:8000/wywy/
访问
http://10.0.8.2:8000/abc
时,结果为:Location: http://10.0.8.2:8000/abcwywy/
-
正则部分表示匹配所有,跳转地址为斜杠开头的资源
/wywy/
访问
http://10.0.24.204/
时,结果为:Location: http://10.0.24.204/wywy/
访问
http://10.0.24.204/abc/xyz
时,结果为:Location: http://10.0.24.204/wywy/
⚠️注意abc/xyz被覆盖访问
http://10.0.8.2:8000
时,结果为:Location: http://10.0.8.2/wywy/
⚠️注意端口号消失访问
http://10.0.8.2:8000/abc/xyz
时,结果为:Location: http://10.0.8.2/wywy/
⚠️注意端口号消失,而且abc也被覆盖如上述rewrite规则,当省略协议、地址端口,资源以斜杠开头时,nginx会根据默认规则默认帮你在斜杠
/
之前填写上协议、地址和端口。你的请求URI部分会被忽略掉。如果你没有自定义重定向配置,那规则就是absolute_redirect on 使用绝对URL,server_name_in_redirect off 使用用户请求输入URL的服务器部分,port_in_redirect on 加入本地监听的的端口号,但是除443、80外。由于本地监听了80,所以此处不会增加端口号,所以端口号消失了。
所以就变成了你请求时的协议(http)+ 你请求时的host(10.0.24.204或者10.0.8.2)+你定义的转跳地址(/wywy/)
-
正则部分表示匹配所有,跳转地址为非斜杠开头的资源
wywy/
访问
http://10.0.24.204/
时,结果为:Location: wywy/
访问
http://10.0.24.204/abc
时,结果为:Location: wywy/
,浏览器跳转地址为http://10.0.24.204/abc/wywy/
访问
http://10.0.8.2:8000
时,结果为:Location: wywy/
, 浏览器跳转地址为http://10.0.8.2:8000/wywy/
访问
http://10.0.8.2:8000/abc/xyz
时,结果为:Location: wywy/
, 浏览器跳转地址为http://10.0.8.2:8000/abc/wywy/
⚠️注意这里相对路径,只针对你访问资源的级别,如最后一个例子,仅仅xyz被替换成wywy/,如果你访问abc/xyz/的话,最终你将得到abc/xyz/wywy/
-
正则部分表示,匹配斜杠开头并不以斜杠结尾,跳转地址为绝对路径的/wywy/
效果同3
-
正则部分表示,匹配斜杠开头并不以斜杠结尾,跳转地址为相对路径的wywy/
效果同4
网友评论