一、Nginx如何处理location定义的URI?
假设你的网站是henchat.net,这里以最简单的URI/xxx为例:
场景①:转发请求到服务器
location /xxx {
proxy_pass http://127.0.0.1:8000;
}
场景②:转发请求到root目录
location /xxx {
root /var/www/xxx;
}
此时如果用户访问 https://henchat.net/xxx ,和直觉不同:
- 在场景①中,以上写法并不会将HTTP请求转发到 http://127.0.0.1:8000 ,而是会转发到后端 http://127.0.0.1:8000/xxx 。后端如果没有定义
/xxx的动作则会出错。 -
同理,在场景②中,https://henchat.net/xxx 访问的目录实际上变成了
/var/www/xxx/xxx。该路径如果不存在则会报错。
二、用rewrite改变Nginx对location的处理
很多时候,我们实际想做的是:当用户访问 https://henchat.net/xxx 时,Nginx将用户请求转发到 http://127.0.0.1:8000 而不是 http://127.0.0.1:8000/xxx 。此时可以用rewrite命令改变转发行为(非严谨写法,实际使用时建议定义URI的开头结尾):
location /xxx {
rewrite /xxx / break;
proxy_pass http://127.0.0.1:8000;
}
这样在Nginx解析location时,会将URI/xxx重写为/传给后端服务器。
如果希望转发URI后面的path,比如将 https://henchat.net/xxx/a.htm 转发到 http://127.0.0.1:8000/a.htm ,更严谨的写法应该是这样:
location /xxx {
rewrite ^/xxx/(.*)$ /$1 break;
proxy_pass http://127.0.0.1:8000;
}
即在解析时将URI重写为/xxx/后面的路径$1并传递给后端。(.*)是正则表达式的捕获组,其值会存入$1。这样,/xxx/a.htm就会被重写为/a.htm。
三、不同location写法对Nginx动作的影响
在Nginx的反向代理设置中,location定义的路径一般会有以下几种写法:
location /xxx
location /xxx/
location = /xxx
location = /xxx/
location ~* ^/xxx
location ~ ^/(xxx|yyy)
1. /xxx 写法
匹配所有以/xxx开头的URI,包括:
/xxx(完全匹配)
/xxx/(末尾带斜杠)
/xxx/abc(子路径)
/xxx123(前缀相同但非路径分隔)
2. /xxx/ 写法
只匹配以/xxx/开头的URI,例如:
/xxx/(完全匹配)
/xxx/abc(子路径)
3. = /xxx 写法
只匹配/xxx。
4. = /xxx/ 写法
只匹配/xxx/。
5. ~* ^/xxx 写法
该写法表明此URI是一个不区分大小写(*)的正则表达式(~)。^是正则表达式的一部分,表示匹配必须从URI的开头开始。
6. ~ ^/(xxx|yyy) 写法
也是一种正则表达式的写法,表示匹配多个URI。
