Nginx 是最常用的反向代理工具之一,一个指令 proxy_pass搞定反向代理,对于接口代理、负载均衡很是实用,但 proxy_pass指令后面的参数很有讲究,通常一个/都可能引发一个血案。
通常nginx配置proxy_pass指令时,如果proxy_pass后面的url加/,表示绝对根路径;如果没有/,表示相对路径,把匹配的路径部分代理上。
url 只是 host,不带/
例如:
-
http://host - √
-
https://host - √
-
http://host:port - √
-
https://host:port - √
-
http://host/ - x
-
http://host:port/ - x
这时候 location匹配的完整路径将直接透传给 url ,如:
// 访问: / 代理: /
// 访问: /api/xx 代理: /api/xx
// 访问: /api/xx?aa 代理: /api/xx?aa
location / {
proxy_pass http://sevice;
}
// 访问: /api/ 代理: /api/
// 访问: /api/xx 代理: /api/xx
// 访问: /api/xx?aa 代理: /api/xx?aa
// 访问: /api-xx?aa 代理: 不匹配
location /api/ {
proxy_pass http://sevice;
}
// 访问: /api/ 代理: /api/
// 访问: /api/xx 代理: /api/xx
// 访问: /api/xx?aa 代理: /api/xx?aa
// 访问: /api-xx?aa 代理: /api-xx?aa
location /api {
proxy_pass http://sevice;
}
url 包含路径
注意,这里的路径哪怕只是一个 / 也是存在的,如:
-
http://host - x
-
https//host/ - √
-
http://host:port - x
-
https://host:port/ - √
-
http://host/api - √
-
http://host/api/ - √
当 proxy_pass url 的 url 包含路径时,匹配时会根据 location 的匹配后的链接透传给 url ,注意匹配后就是这样:
location 规则 | 访问的原始链接 | 匹配之后的路径 |
---|---|---|
location / | / | |
location / | /a | a |
location / | /a/b/c?d | a/b/c?d |
location /a/ | /a/ | |
location /a/ | /a/b/c?d | b/c?d |
在 proxy_pass url 包含路径时,将会把匹配之后的路径透传给 url,如:
// 访问: / 代理: /
// 访问: /api/xx 代理: /api/xx
// 访问: /api/xx?aa 代理: /api/xx?aa
location / {
proxy_pass http://service/;
}
// 访问: /api/ 代理: /
// 访问: /api/xx 代理: /xx
// 访问: /api/xx?aa 代理: /xx?aa
// 访问: /api-xx?aa 代理: 未匹配
location /api/ {
proxy_pass http://service/;
}
// 访问: /api 代理: /
// 访问: /api/ 代理: //
// 访问: /api/xx 代理: //xx
// 访问: /api/xx?aa 代理: //xx?aa
// 访问: /api-xx?aa 代理: /-xx?aa
location /api {
proxy_pass http://service/;
}
// 访问: /api/ 代理: /v1
// 访问: /api/xx 代理: /v1xx
// 访问: /api/xx?aa 代理: /v1xx
// 访问: /api-xx?aa 代理: 未匹配
location /api/ {
proxy_pass http://service/v1;
}
// 访问: /api/ 代理: /v1/
// 访问: /api/xx 代理: /v1/xx
// 访问: /api/xx?aa 代理: /v1/xx
// 访问: /api-xx?aa 代理: 未匹配
location /api/ {
proxy_pass http://service/v1/;
}
重写代理链接 - url rewrite
当原始链接(浏览器访问的链接)和代理服务器链接规则不一致时,可以使用 Nginx URL Rewrite 功能去动态的重写,如:
location ~* ^/api/ {
rewrite ^/api/(.*) /?path=$1 break;
proxy_pass http://node:8080;
}
以上请求会把匹配 /api/的链接重写为 /?path=的链接透传给 node:8080 服务,有意思的是当使用 rewrite指令并且生效后,proxy_pass url链接中的路径会被忽略,如:
// 访问: / 代理: /node/
// 访问: /api 代理: /node/api
// 访问: /api/ 代理: /?path=
// 访问: /api/a/b/c 代理: /?path=a/b/c
location / {
rewrite ^/api/(.*) /?path=$1 break;
proxy_pass http://node:8080/node/;
}