折腾了半天,才发现就少了一个分号
那天给一个新接口加反向代理,我在 Nginx 里加了个 location:
写完 nginx -t,返回 syntax is ok,test successful。我放心地 nginx -s reload,下班。
第二天一早,后端同事在群里说:接口全 404 了,而且收到的 Host 头长得莫名其妙,像 xxx proxy_set_header X-Real-IP yyy 这种一长串。
我自信满满地开始排查。
- 是不是 proxy_pass 写错了?地址对,后端服务在跑,curl 直连后端正常。
- 是不是后端路由的问题?后端说直连能路由,走 Nginx 就 404,问题在前面。
- 是不是 Host 头被改了导致后端虚拟主机匹配不上?但我只设了一个
Host $host,能改成啥?
- 是不是 Nginx 版本的 bug?查了 changelog,没有相关 issue。
- 是不是某个 upstream 缓存了旧配置?reload 了三四次,现象不变。
- 是不是中间有个防火墙在改头?抓包看了一下,头确实是在 Nginx 出去时就乱了。
一个上午就在这种"配置测过了、后端没问题、但头就是乱的"里过去了。我甚至把整个 server 块删了重写——重写完居然好了。然后我 diff 了两版配置,肉眼看不出区别。
快午饭的时候,我终于做了一件早就该做的事:把配置贴到编辑器里,开了"显示空白字符"。
然后我看到了:proxy_set_header Host $host 这一行末尾,没有分号。
熟悉 Nginx 的人这时候大概要笑出声了。
Nginx 配置里,指令以分号结束,空格和换行都只是分隔参数的空白。漏了那个分号,解析器会把下一行也当成同一条指令的参数继续读,直到遇到下一个分号为止。
于是我的两条指令:
在 Nginx 眼里变成了一条:
proxy_set_header 接受的是"头名 + 值",它把后面一整串 $host proxy_set_header X-Real-IP $remote_addr 全塞进了 Host 头的值里。X-Real-IP 那条指令压根没被单独识别,等于没设。
更阴险的是:这种"参数多了几个"的情况,nginx -t 不报错——因为语法上它是合法的,proxy_set_header 不限制值的长度。所以测试通过,上线翻车。
补上那个分号,reload,全世界都清净了。
折腾半天换来的几句话,送给每一个觉得"nginx -t 过了就没事"的人:
nginx -t只查语法,不查语义。 它能发现少花括号、拼错指令名,但发现不了"漏分号导致指令被吞"——因为吞掉之后语法仍然合法。配置测过了不等于配置是对的,尤其涉及proxy_set_header、rewrite、try_files这些多参数指令。
- 每条指令末尾的分号,必须亲手确认。 别相信肉眼——编辑器开"显示尾随空白"或"高亮行尾分号"能救命。粘贴片段后第一件事就是扫一遍分号,比 reload 出事再排查快一百倍。
- Host 头乱码、后端莫名 404,先查 proxy_set_header 的分号。 这是一个非常典型的症状:头值里混进了下一条指令的名字。看到 Host 头变长、带奇怪关键字,八成是漏分号了。
- 改 Nginx 配置用 diff 思维。 出问题时把当前配置和上一个能跑的版本 diff 一下,再小的差异都别放过——这次要不是重写一遍碰巧对了,我可能还在怀疑后端。
- 点赞
- 收藏
- 关注作者
评论(0)