LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

Nginx路由的诡异现象:相同前缀请求为何走向不同终点?

admin
2025年9月5日 14:55 本文热度 86

昨天遇到一个 nginx 下非常诡异(其实也不算难,思路对了也就1秒钟的事情)的现象,花了2个小时才找到问题并解决,问题的现象还是第一次遇到,记录下,方便以后的自己和遇到类似问题的同学。

PS:下面文章内容,是deepseek根据我们的对话记录生成的。本来想自己写的,但自己写还是太慢了点,为了积极践行 降本增效 的大方针,还是用更加高效的AI来吧

相关URL、IP等信息已经脱敏处理

一次Nginx临时目录权限引发的"诡异"路由问题排查记

看似相同的请求为何走向不同的终点?一次权限问题引发的深度排查

问题现象:两条相似的请求,不同的目的地

在日常运维中,我遇到了一个奇怪的问题:两个具有相同路径前缀的HTTP请求,竟然被Nginx转发到了不同的上游服务器。

查看Nginx访问日志,发现了这样的记录:

192.168.1.100 - - [02/Sep/2025:17:07:45 +0800] "POST /api/service/v1/file/upload HTTP/1.0" 502 559 "https://example.com/static/webapp/v1/" "Mozilla/5.0 (Linux; Android 15; Build/AQ3A.240912.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/131.0.6778.260 Mobile Safari/537.36" upstream_addr=127.0.0.1:9001 upstream_status=502 upstream_response_time=0.001 request_time=0.001

192.168.1.100 - - [02/Sep/2025:17:08:32 +0800] "POST /api/service/v1/user/item/addItem HTTP/1.0" 200 95 "https://example.com/static/webapp/v1/" "Mozilla/5.0 (Linux; Android 15; Build/AQ3A.240912.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/131.0.6778.260 Mobile Safari/537.36" upstream_addr=192.168.10.20:8080 upstream_status=200 upstream_response_time=0.124 request_time=0.125

从日志可以看出,两个请求都有相同的路径前缀/api/service/v1/,但第一个请求被转发到了127.0.0.1:9001并返回502错误,第二个请求则被正确转发到了192.168.10.20:8080并返回200成功。

排查过程:一步步揭开迷雾

第一阶段:增强日志,确认问题

首先,我们在Nginx配置中增加了详细的日志格式,希望能够捕获更多信息:

log_format detailed '$remote_addr - $remote_user [$time_local] "$request" '
                   '$status $body_bytes_sent "$http_referer" "$http_user_agent" '
                   'upstream_addr=$upstream_addr upstream_status=$upstream_status '
                   'uri=$uri request_uri=$request_uri';

access_log /var/log/nginx/detailed_access.log detailed;

启用详细日志后,我们确认了两个具有相同前缀的请求确实被路由到了不同的upstream,这与预期行为不符。

第二阶段:排查location配置

我们检查了Nginx配置,发现有两个location块:

location /api/service/v1/ {
    proxy_pass http://192.168.10.20:8080/api/;
}

location / {
    proxy_pass http://127.0.0.1:9001/;
}

按照Nginx的最长前缀匹配原则,两个请求都应该匹配到第一个location块。但实际情况并非如此。

为了排除默认location的干扰,我们尝试注释掉了第二个location块:

# location / {
#     proxy_pass http://127.0.0.1:9001/;
# }

重启Nginx后,惊讶地发现被错误转发请求的upstream_addr变成了空,这表明请求根本没有被正确代理到任何上游服务器。

第三阶段:发现关键错误日志

在前两个阶段都没有找到根本原因后,我们几乎是无意中查看了Nginx的错误日志( error.log ) ,这才发现了关键线索:

2025/09/03 07:58:41 [crit] 1340742#0: *277929 open() "/usr/local/nginx/client_body_temp/0000000054" failed (13: Permission denied), client: 192.168.1.100, server: example.com, request: "POST /api/service/v1/file/upload HTTP/1.0", host: "api.example.com", referrer: "https://example.com/static/webapp/v1/"

这个错误信息很关键——Nginx进程没有权限在临时目录中创建文件

根源分析:临时目录与Nginx的fallback机制

1. Nginx如何处理大请求体

当Nginx处理客户端请求时,如果请求体较小,会使用内存缓冲区直接处理。但当请求体较大(超过client_body_buffer_size设置)时,Nginx会将请求体写入临时文件中,以避免占用过多内存。

2. 权限失败引发的连锁反应

当第一个请求(文件上传)到达时:

  • 由于请求体较大,Nginx尝试将其写入临时文件
  • 但Nginx worker进程没有临时目录的写权限
  • 写入失败,导致请求处理中断
  • 触发了Nginx的错误处理机制,将请求fallback到默认location

而第二个请求(普通API调用):

  • 请求体较小,不需要写入临时文件
  • 因此没有触发权限错误
  • 正常匹配到预期的location块

解决方案:创建有权限的临时目录

通过以下步骤解决了这个问题:

1. 创建有权限的临时目录

mkdir -p /tmp/nginx_temp/client_body_temp

2. 在nginx.conf中配置临时目录路径

在http块中添加配置:

http {
    # 其他配置...

    # 指定临时目录到有权限的位置
    client_body_temp_path /tmp/nginx_temp/client_body_temp;

    # 其他配置...
}

3. 确保Nginx进程有读写权限

chown -R nginx:nginx /tmp/nginx_temp/client_body_temp
chmod -R 755 /tmp/nginx_temp/client_body_temp

4. 重新加载Nginx配置

nginx -s reload

经验总结与反思

这次排查经历给了我们几个重要启示:

  1. 日志是关键:没有详细的访问日志和错误日志,很难快速定位问题
  2. 排查要有系统性:从表象到本质,从access.log到error.log,需要有条不紊地进行
  3. 权限问题很隐蔽:Nginx的权限问题往往表现为其他症状,需要深入挖掘
  4. 默认配置可能不适用:生产环境中需要明确指定各种路径和权限,不能依赖默认值

排查过程中的关键步骤

  1. 增加详细日志记录,确认问题现象
  2. 分析Nginx配置,理解预期行为
  3. 通过修改配置(注释默认location)缩小问题范围
  4. 检查错误日志,发现根本原因
  5. 实施修复并验证效果

预防措施与最佳实践

为了避免类似问题,建议采取以下措施:

# 示例:完整的客户端请求体配置
http {
    client_max_body_size 100M;
    client_body_buffer_size 16k;
    client_body_temp_path /var/tmp/nginx_client_temp;
    client_body_timeout 60s;

    # 确保目录存在且有权限
    # mkdir -p /var/tmp/nginx_client_temp
    # chown -R nginx:nginx /var/tmp/nginx_client_temp
    # chmod -R 755 /var/tmp/nginx_client_temp
}


亲爱的读者朋友们,欢迎在评论区分享你的经验和见解!

🎯 讨论话题:

  1. 你在使用Nginx过程中遇到过哪些"诡异"的问题?最后是如何解决的?
  2. 关于Nginx的权限管理,你有哪些最佳实践想要分享?
  3. 本文的排查思路对你是否有启发?你会如何避免类似的坑?

💡 如果你觉得这篇文章对你有帮助:

  • 点赞支持一下,让更多小伙伴看到这篇干货
  • 关注我们,获取更多运维实战经验和技巧分享
  • 收藏文章,遇到类似问题时随时回来查阅

🔍 延伸思考:

  • 除了临时目录权限,还有哪些看似小却可能引发大问题的Nginx配置细节?
  • 在你的生产环境中,是如何监控和预防这类权限问题的?


阅读原文:原文链接


该文章在 2025/9/8 9:33:29 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2025 ClickSun All Rights Reserved