Nginx Proxy Pass问题排查:Docker、React与Express环境
我来帮你拆解下为什么只有加尾斜杠才能正常工作:
当你调用process.env.PUBLIC_URL + "/api"时,最终请求路径是/todos/api,经过入口Nginx的rewrite后,传给二级Nginx的路径是/api(不带尾斜杠)。而你二级Nginx里的rewrite /api/(.*) /$1 break;规则只会匹配带有/api/后缀的路径(比如/api/xxx),对于单纯的/api请求,这条rewrite完全不会触发。此时proxy_pass到todoserver时,请求路径还是/api,而你的Express API根路由是/,自然就匹配不上了。
而当你加了尾斜杠变成/api/时,入口Nginx转成/api/,二级Nginx的rewrite规则命中,把路径改成/,刚好匹配Express的根路由,所以能正常工作。
接下来给你两个可行的解决方案,任选其一即可:
方案一:修改二级Nginx的rewrite规则,兼容带/不带尾斜杠的请求
把二级Nginx中/api的location块改成这样:
location /api { # 匹配/api 或/api/xxx的请求,统一重写为对应的路径(/ 或/xxx) rewrite ^/api(/.*)?$ $1 break; proxy_pass http://todoserver/; # 建议加上这些proxy头,避免Express端获取不到正确的请求信息 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; }
这个正则^/api(/.*)?$会匹配两种情况:
- 精确的
/api:此时$1为空,rewrite后路径是/ api/xxx:此时$1是/xxx,rewrite后路径是/xxx
这样不管请求带不带尾斜杠,都能正确映射到Express的对应路由。
方案二:让Nginx自动处理尾斜杠重定向(可选)
如果你不介意浏览器端有一次301重定向,可以在二级Nginx的/apilocation里先加一条重定向规则,把不带尾斜杠的请求转成带尾斜杠的:
location /api { # 先把/api重定向到/api/,这样后续的rewrite规则就能正常触发 rewrite ^/api$ /api/ permanent; rewrite /api/(.*) /$1 break; proxy_pass http://todoserver/; # 同样加上必要的proxy头 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的匹配逻辑,但缺点是会多一次重定向请求,适合对重定向不敏感的场景。
额外建议:优化入口Nginx的配置
你的入口Nginx/todos的location里用了rewrite /todos/(.*) /$1 break;,其实可以改成更严谨的正则匹配,避免一些边缘情况:
location ^~ /todos { rewrite ^/todos(/.*)?$ $1 break; proxy_intercept_errors on; 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; proxy_pass http://todosnginx/; }
用^~ /todos可以让这个location优先匹配,避免和其他可能的location规则冲突,同时rewrite规则也兼容/todos和/todos/xxx的请求。
最后,修改完配置后,记得重启对应的Nginx容器,让配置生效哦!
内容的提问来源于stack exchange,提问作者Raph117

