You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Nginx配置resolver+proxy_pass+变量后出现404问题排查

Nginx配置DNS resolver后请求返回404的原因及解决办法

问题背景

为避免上游DNS未就绪时Nginx服务崩溃,通过set指令引用环境变量FOO_SERVER_SOCKET_IO_URL并添加resolver配置后,Nginx能正常启动,但访问/foo-server/socket.io路径时返回404错误。

原配置(环境变量未定义时会崩溃)

server {
  listen 80;

  gzip on;
  gzip_disable "msie6";

  gzip_vary on;
  gzip_proxied any;
  gzip_comp_level 6;
  gzip_buffers 16 8k;
  gzip_http_version 1.1;
  gzip_min_length 0;
  gzip_types text/plain application/javascript text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype;

  location / {
    root   /usr/share/nginx/html;
    index  index.html index.htm;
    try_files $uri $uri/ /index.html;
  }

  location /foo-server/socket.io {
    proxy_pass ${FOO_SERVER_SOCKET_IO_URL}/socket.io;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
  }

  ...

  error_page 500 502 503 504 /50x.html;

  location = /50x.html {
    root  /usr/share/nginx/html;
  }
}

修改后的配置(启动正常但返回404)

server {
  listen 80;
  resolver 127.0.0.11 valid=60s ipv6=off;
  resolver_timeout 10s;

  gzip on;
  gzip_disable "msie6";
  gzip_vary on;
  gzip_proxied any;
  gzip_comp_level 6;
  gzip_buffers 16 8k;
  gzip_http_version 1.1;
  gzip_min_length 0;
  gzip_types text/plain application/javascript text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype;

location / {
    root   /usr/share/nginx/html;
    index  index.html index.htm;
    try_files $uri $uri/ /index.html;
  }

  location /foo-server/socket.io {
    set $foo_server_socket_io $FOO_SERVER_SOCKET_IO_URL;
    proxy_pass $foo_server_socket_io/socket.io;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
  }

  ...

  error_page 500 502 503 504 /50x.html;

  location = /50x.html {
    root  /usr/share/nginx/html;
  }
}

相关Nginx日志

2024-02-13 16:05:35 192.168.65.1 - - [13/Feb/2024:15:05:35 +0000] "GET /foo-server/socket.io/?EIO=4&transport=polling&t=OsZ086l HTTP/1.1" 404 147 "http://localhost:3000/foo-path" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36" "-"

原因分析

当proxy_pass使用变量时,Nginx不会自动截断当前location的匹配路径,而是会把完整的请求URI(包括/foo-server/socket.io)拼接到代理地址后面。

举个例子:如果FOO_SERVER_SOCKET_IO_URL是http://foo.example.com,原配置中proxy_pass ${FOO_SERVER_SOCKET_IO_URL}/socket.io会把请求代理到http://foo.example.com/socket.io/?xxx;但修改后用变量的情况下,实际代理的地址会变成http://foo.example.com/socket.io/foo-server/socket.io/?xxx,上游服务器找不到该路径,因此返回404。

解决方案

需要手动剔除location匹配的前缀,调整proxy_pass的写法,推荐修改location块如下:

location /foo-server/socket.io {
  set $foo_server_socket_io $FOO_SERVER_SOCKET_IO_URL;
  # 剔除/foo-server前缀,只保留/socket.io及后续路径
  rewrite ^/foo-server(.*)$ $1 break;
  proxy_pass $foo_server_socket_io;
  proxy_http_version 1.1;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection 'upgrade';
  proxy_set_header Host $host;
  proxy_cache_bypass $http_upgrade;
}

或者直接构造正确的代理路径(注意FOO_SERVER_SOCKET_IO_URL末尾不要带/,避免出现重复的//):

location /foo-server/socket.io {
  set $foo_server_socket_io $FOO_SERVER_SOCKET_IO_URL;
  proxy_pass $foo_server_socket_io$request_uri;
  proxy_http_version 1.1;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection 'upgrade';
  proxy_set_header Host $host;
  proxy_cache_bypass $http_upgrade;
}

内容的提问来源于stack exchange,提问作者Balint Laszlo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 03:37:03