news 2026/7/2 3:00:16

记一次 Nginx 代理导致 API 500 错误的排查与修复

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
记一次 Nginx 代理导致 API 500 错误的排查与修复

记一次 Nginx 代理导致 API 500 错误的排查与修复

问题描述

前端访问http://localhost:9527/dev-api/Login/getStaticResource返回 500 Internal Server Error,直接访问http://anyu-portal.test/正常。

技术栈

  • 前端:Vue.js + Vue CLI (devServer proxy)
  • 后端:ThinkPHP 5.x + PHP 7.4
  • 容器:Docker Compose (nginx, php-fpm)
  • 代理:Nginx 反向代理

请求链路分析

浏览器 localhost:9527/dev-api/Login/getStaticResource ↓ Vue devServer proxy (vue.config.js) Nginx anyu-portal-frontend.test/api/Login/getStaticResource ↓ Nginx location /api/ proxy_pass (anyu-front.conf) Nginx anyu-portal.test/Login/getStaticResource ↓ Nginx location ~ .php$ fastcgi_pass (anyu-portal.conf) PHP-FPM anyu-portal/Public/index.php

配置文件检查

1. Vue devServer 代理配置

vue.config.js

proxy:{[process.env.VUE_APP_BASE_API]:{target:'http://anyu-portal-frontend.test/api',changeOrigin:true,pathRewrite:{['^'+process.env.VUE_APP_BASE_API]:''}}}

VUE_APP_BASE_API=/dev-api,所以:

  • 请求/dev-api/Login/getStaticResource
  • 被转发到http://anyu-portal-frontend.test/api/Login/getStaticResource

2. Nginx 前端站点配置

anyu-front.conf

server { listen 80; server_name anyu-frontend.test *.anyu-frontend.test; root "/www/anyu-portal-frontend"; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_set_header Host $http_x_forwarded_host; proxy_pass http://anyu-portal.test/; } }

3. Nginx 后端站点配置

anyu-portal.conf

server { listen 80; server_name anyu-portal.test; root /www/anyu-portal/Public; if (!-e $request_filename) { rewrite ^(.*)$ /index.php?s=$1 last; } location ~ \.php$ { fastcgi_pass php:9000; include fastcgi-php.conf; include fastcgi_params; } }

4. Docker Compose 网络配置

docker-compose.yml

services:nginx:extra_hosts:-"openapi:127.0.0.1"-"lvs:127.0.0.1"-"admin:127.0.0.1"-"portal:127.0.0.1"# 缺少: anyu-portal.test:127.0.0.1

排查过程

步骤 1:直接测试后端 API

从 nginx 容器内部直接访问后端:

dockerexecnginxcurl-vhttp://anyu-portal.test/Login/getStaticResource

结果:返回 200 OK,后端 API 本身正常。

步骤 2:测试代理链路

从 nginx 容器内部通过前端域名访问:

dockerexecnginxcurl-vhttp://anyu-portal-frontend.test/api/Login/getStaticResource

结果:返回 500 Internal Server Error。

步骤 3:检查 Host 头问题

直接访问时 curl 会发送Host: anyu-portal.test,但通过/api/代理时:

proxy_set_header Host $http_x_forwarded_host;

$http_x_forwarded_host是客户端请求的X-Forwarded-Host头,通常为空。当 Host 头为空时,后端 ThinkPHP 的getStaticResource方法无法正确识别SERVER_NAME,导致找不到合作伙伴配置。

步骤 4:检查域名解析

nginx 容器的extra_hosts中没有配置anyu-portal.test,虽然之前已经添加了,但需要确认是否生效。

根因分析

问题有两个层面:

  1. Host 头为空proxy_set_header Host $http_x_forwarded_host;设置了一个通常为空的变量,导致转发到后端时没有正确的 Host 头。

  2. 域名解析:nginx 容器内部无法解析anyu-portal.test(虽然之前已添加到extra_hosts)。

后端 ThinkPHP 的getStaticResource方法依赖SERVER_NAME获取合作伙伴配置:

publicfunctiongetStaticResource(){$server_name=SERVER_NAME;// 依赖 $_SERVER['SERVER_NAME']$redis=newRedis();$redis->connect(C("REDIS_HOST"),C("REDIS_PORT"));// ...if(!C('PARTNER')){$this->setPartner($redis,$server_name);// 根据 server_name 获取合作伙伴}// ...}

当 Host 头为空或不正确时,SERVER_NAME无法正确识别,导致C('PARTNER')为空,后续操作失败。

修复方案

修复 1:修改 Nginx 代理配置

文件services/nginx/conf.d/anyu-front.conf

# 修改前 location /api/ { proxy_set_header Host $http_x_forwarded_host; proxy_pass http://anyu-portal.test/; } # 修改后 location /api/ { proxy_set_header Host anyu-portal.test; proxy_pass http://anyu-portal.test/; }

修复 2:添加域名解析

文件docker-compose.yml

services:nginx:extra_hosts:-"openapi:127.0.0.1"-"lvs:127.0.0.1"-"admin:127.0.0.1"-"portal:127.0.0.1"-"anyu-portal.test:127.0.0.1"# 新增

修复 3:重载 Nginx 配置

dockerexecnginx nginx-sreload

验证

dockerexecnginxcurl-vhttp://anyu-portal-frontend.test/api/Login/getStaticResource

结果:返回 200 OK,JSON 数据正常。

总结

经验教训

  1. Host 头很重要:反向代理时,proxy_set_header Host必须设置正确的值,后端框架(如 ThinkPHP)依赖它来识别当前站点。

  2. 容器内部域名解析:Docker Compose 的extra_hosts只对容器内部生效,宿主机的 hosts 文件不会自动同步到容器。

  3. 排查顺序:先测试直接访问后端,再测试完整代理链路,定位问题出在哪一层。

  4. 变量陷阱$http_x_forwarded_host是客户端请求头,不是 Nginx 内置变量,不要误以为它会自动填充。

最佳实践

location /api/ { proxy_set_header Host $proxy_host; # 使用 proxy_pass 中指定的主机名 proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://backend/; }

使用$proxy_host可以自动获取proxy_pass中指定的主机名,比硬编码更灵活。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/2 2:59:44

【新品发布】AI PC快充防护再进阶!艾为电子推出Type‑C OVP系列产品

随着 AI PC 算力持续跃升、性能全力释放,设备功耗与补能需求大幅提升,大功率快充已然成为行业不可逆发展趋势。传统 100W 以下快充规格早已难以满足高性能 AI 终端的使用需求,PC 快充功率正式迈入阶梯式升级通道,形成65W→100W→1…

作者头像 李华
网站建设 2026/7/2 2:56:44

一个由进程内存布局异常引起的问题

前段时间业务反映某类服务器上更新了 bash 之后,ssh 连上去偶发登陆失败,客户端吐出错误信息如下所示: 图 - 0 该版本 bash 为部门这边所定制,但是实现上与原生版并没有不同,那么这些错误从哪里来? 是 …

作者头像 李华
网站建设 2026/7/2 2:55:38

贵阳婚纱照拍的最好的是哪一家?

说实话,在贵阳备婚这件事里,“拍婚纱照是最容易让人纠结的一步”。 我当时的状态很典型: 一边刷到各种“3999全包”“零隐形消费”的套餐,一边又看到身边朋友吐槽“拍完加钱、修图加钱、服装还分档次”。 更现实的是—— 你以为选…

作者头像 李华
网站建设 2026/7/2 2:52:57

容器资源限制与配额管理实践

容器资源限制与配额管理实践随着容器化技术的普及,尤其是以Docker和Kubernetes为代表的平台成为云原生应用的基石,如何高效、安全地管理容器资源,确保应用性能与稳定性,同时提升基础设施利用率,已成为运维与开发团队面…

作者头像 李华
网站建设 2026/7/2 2:52:51

Rust语言基础开发教程

Rust语言基础开发教程:构建安全高效的系统级应用引言:为什么选择Rust?在当今的编程语言生态中,Rust以其独特的内存安全保证、卓越的性能表现和出色的并发处理能力脱颖而出。作为一门系统级编程语言,Rust不仅提供了C/C级…

作者头像 李华