跳至正文

我靠,Nginx 配置里一个 0 就把我坑了,整个网站慢了 3 倍

事情是这样的。上周三下午,我正在工位摸鱼刷知乎,突然运维老张在群里炸了锅,说线上一个 API 接口响应时间从 200ms 飙到了 600ms,用户反馈已经开始炸了。我心想这关我屁事,我是写业务逻辑的,又不是搞运维的。结果老张直接 @ 我,说这个接口是你写的,你看看是不是代码有问题。

我查了 2 个小时代码,SQL 优化了一遍,索引该加的加了,Redis 缓存也怼上了,本地压测一切正常。但一上生产,就是慢。这时候我突然想起,这个接口前两天刚接了个 CDN 回源的需求,我在 Nginx 里加了个 rewrite 规则。赶紧去翻了一下配置,一看差点没把午饭喷出来。

问题出在 Nginx 的 proxy_pass 上。我原来写的是这样的:

“`
location /api/ {
proxy_pass http://backend;
}
“`

后来为了配合 CDN 回源,改成了这样:

“`
location /api/ {
rewrite ^/api/(.*) /$1 break;
proxy_pass http://backend/;
}
“`

注意那个 proxy_pass 后面的斜杠。Nginx 的 proxy_pass 有个天坑:如果它后面不带 URI,比如直接写 `http://backend`,那么请求的 URI 会原封不动地透传给后端。但如果带了斜杠,比如 `http://backend/`,Nginx 就会把 location 匹配的部分给吃掉,然后把剩下的部分拼上去。

拿一个具体请求举例。用户请求 `/api/user/profile`,走 rewrite 之后变成了 `/user/profile`,然后 proxy_pass 是 `http://backend/`。Nginx 会把 `location /api/` 匹配到的 `/api/` 部分去掉,剩下 `/user/profile`,最终请求后端变成 `http://backend/user/profile`。看起来没问题对吧?

但问题出在 Nginx 1.18.0 版本的一个行为差异上。当 proxy_pass 带斜杠的时候,Nginx 会尝试对 URI 进行二次规范化处理。如果 rewrite 改写后的 URI 里包含了某些特殊字符或者路径穿越符号,Nginx 会重新解析一遍。我的业务里有个参数是 base64 编码的,里面带了 `//` 这种双斜杠,Nginx 解析的时候直接把它给合并了,导致后端收到的请求路径变了,然后后端应用又去查路由表,匹配不到直接返回 404,前端再重试,一来一回,3 倍的延迟就这么出来了。

解决方法其实就一行:把 proxy_pass 后面的斜杠去掉。

“`
location /api/ {
rewrite ^/api/(.*) /$1 break;
proxy_pass http://backend;
}
“`

这样 Nginx 就不会自作主张去处理 URI 了,rewrite 改完之后是什么就是什么,原样透传给后端。改完重启 Nginx,接口立马回到 200ms。

踩完这个坑我总结了两条铁律。

第一,Nginx 里 proxy_pass 带不带斜杠,不是风格问题,是语义问题。带斜杠等于告诉 Nginx“我要替换 location 匹配的部分”,不带斜杠等于“原样转发”。如果你用了 rewrite 改了 URI,最好用不带斜杠的 proxy_pass,否则 Nginx 可能会把你 rewrite 的结果再处理一遍,两次处理不一定等价。

第二,涉及到 URI 里有编码字符的场景,一定要在生产环境用真实流量测一下。我本地测试用的都是简单路径,根本触发不了这个 bug。生产环境里用户的 base64 数据五花八门,双斜杠、百分号编码、甚至中文字符,这些东西在 Nginx 的 URI 处理逻辑里都可能变成定时炸弹。

后来我跟老张说改好了,他问我改了什么,我说去掉了 proxy_pass 后面的一个斜杠。他沉默了三秒,说就这?我说就这。他说你写个文档吧,以后别让其他人再踩一遍。我说行,然后就有了这篇博客。

对了,Nginx 版本是 1.18.0,如果你是 1.20 以上版本,这个行为可能已经变了。但不管版本怎么升级,记住一条:rewrite 和 proxy_pass 一起用的时候,要么你不要在 proxy_pass 里加 URI,要么你就在 rewrite 里把 location 匹配的部分手动拼回去,别让 Nginx 替你干活。它替你干的活,往往都是你不想让它干的。


📎 延伸阅读

看完这篇,如果你想:

  • 直接拿工具 → 回复”13“,我把跨境获客工具包发给你
  • 系统学习 → 点击菜单”AI训练营”,从0开始跑通AI变现

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注