本文所描述的内容,代理地址基于http://127.0.0.1:8080,location块基于/api。
proxy_pass
pass_pass [address];
| 参数 | 说明 |
| address | 需要代理的目标地址 |
如果代理目标地址是/结尾,那么/api则不会添加到目标地址的路径中。例如proxy_pass http://127.0.0.1:8080/;,那么访问proxy_address/api/xxx/xxx,nginx实际请求的是http://127.0.0.1:8080/xxx/xxx。
如果代理目标地址不是/结尾,那么/api会一并添加到路径中。例如proxy_pass http://127.0.0.1:8080;,那么访问proxy_address/api/xxx/xxx,nginx实际请求的是http://127.0.0.1:8080/api/xxx/xxx。
rewrite
rewrite regex replacement [flag];
| 参数 | 说明 |
| regex | 正则表达式,用于匹配请求的 URL |
| replacement | 匹配后替换的 URL |
| flag |
可选参数,控制重写行 last:本次重写完成后,重新匹配新的 URL(类似 return) break:停止匹配后续 rewrite 规则,但继续执行后续 location 配置 redirect:返回 302 临时重定向 permanent:返回 301 永久重定向 |
rewrite ^/api/(.*) /$1 break;匹配/api/后面的路径,同时将新的路径/$1按照proxy_pass的规则添加到proxy_pass地址的后面,当rewrite没有匹配到时,执行默认的proxy_pass规则。
rewrite若要与proxy_pass合用,rewrite必须使用break标志,否则rewrite会覆盖proxy_pass的配置,rewrite应位于proxy_pass之前。
另外补充rewrite,proxy_pass和俩兄弟try_files,return的优先级问题,优先级从高到低依次是:rewrite,return,try_files,proxy_pass。
实际问题
在开发过程中,遇到了一个存在websocket服务的情况,而且websocket地址位于http://127.0.0.1:8080/,也就是服务的根路径上。最开始使用了如下的nginx配置,精准匹配一个子路径/api,这个路径代理http://127.0.0.1/,而其他请求则通过模糊匹配/api去处理,虽然可行,但是这样的配置很麻烦,要写两个location块用于处理一个反代业务。
# Websocket Proxy
location = /api {
# Set up for WebSocket connections
proxy_pass http://127.0.0.1:8080/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Timeout settings
proxy_connect_timeout 3s;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
keepalive_timeout 65;
keepalive_requests 100000;
# Disable buffering for real-time data
proxy_buffering off;
# Performance tuning
proxy_set_header Connection keep-alive;
tcp_nodelay on;
}
location /api {
# Set up for WebSocket connections
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
rewrite ^/api/(.*)$ /$1 break;
}
改进以后的配置如下。
# Websocket Proxy
location /api {
rewrite ^/api/(.*)$ /$1 break;
# Set up for WebSocket connections
proxy_pass http://127.0.0.1:8080/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Timeout settings
proxy_connect_timeout 3s;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
keepalive_timeout 65;
keepalive_requests 100000;
# Disable buffering for real-time data
proxy_buffering off;
# Performance tuning
proxy_set_header Connection keep-alive;
tcp_nodelay on;
}
改进后的配置在访问/api时,如果路径前缀不包含/api/,则不会触发rewrite规则,紧接着触发proxy_pass存在后缀/时的规则。如果路径前缀包含/api/,则触发rewrite规则,同时修改后的路径由proxy_pass继续处理。
以上的配置也可以将location /api改写为locaton /api/,或者是将proxy_pass https://127.0.0.1:8090/;改写为proxy_pass https://127.0.0.1:8090;,都是可以的,相应的逻辑按照pass_proxy和rewrite的规则进行解释即可。
只是如果最后改写为location /api和proxy_pass https://127.0.0.1:8090;,那么在访问路径的时候,就必须与代理前的path一致。比如代理前需要通过http://127.0.0.1:8080/访问ws服务,那么也就必须通过proxy_address/api/访问ws服务。
DISCUSSION
评论
还没有公开评论,欢迎留下想法。