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

Nginx负载均衡对特定UI API请求返回400错误,求问题排查帮助

问题描述

我的应用采用SpringBoot + Angular架构,前端部署了Nginx负载均衡器。目前发现UI发起的某一个API请求会被负载均衡器返回400错误(可在access.log中观测到),但其他UI发起的API请求均正常。

开启debug模式查看错误日志,仅能看到无意义的循环日志,内容如下:

2023/08/04 16:48:46 [debug] 16960#11544: worker cycle
2023/08/04 16:48:46 [debug] 16960#11544: select event: fd:444 wr:0
2023/08/04 16:48:46 [debug] 16960#11544: select event: fd:448 wr:0
2023/08/04 16:48:46 [debug] 16960#11544: select timer: 500
2023/08/04 16:48:47 [debug] 16960#11544: select ready 0
2023/08/04 16:48:47 [debug] 16960#11544: timer delta: 501
2023/08/04 16:48:47 [debug] 16960#11544: worker cycle
2023/08/04 16:48:47 [debug] 16960#11544: select event: fd:444 wr:0
2023/08/04 16:48:47 [debug] 16960#11544: select event: fd:448 wr:0
2023/08/04 16:48:47 [debug] 16960#11544: select timer: 500
2023/08/04 16:48:47 [debug] 12316#19104: select ready 0
2023/08/04 16:48:47 [debug] 12316#19104: timer delta: 501
2023/08/04 16:48:47 [debug] 12316#19104: worker cycle
2023/08/04 16:48:47 [debug] 12316#19104: select event: fd:444 wr:0
2023/08/04 16:48:47 [debug] 12316#19104: select event: fd:448 wr:0
2023/08/04 16:48:47 [debug] 12316#19104: select timer: 500
2023/08/04 16:48:47 [debug] 12316#19104: select ready 0
2023/08/04 16:48:47 [debug] 12316#19104: timer delta: 501
2023/08/04 16:48:47 [debug] 12316#19104: worker cycle

我的Nginx负载均衡器配置如下:

#user  nobody;
worker_processes  1;

error_log  logs/error.log  debug;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
    # Debugging a certain IP
    debug_connection 2.2.2.2; # client getting http 400 errors
}


http {
    include       mime.types;
    default_type  application/octet-stream;
    
    large_client_header_buffers 16 128k;
    
    include /etc/nginx/modules-enabled/*.conf;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
     #                 '"$http_user_agent" "$http_x_forwarded_for"';
                       
  log_format upstream_time '$remote_addr - $remote_user [$time_local] '
         '"$request" $status $body_bytes_sent '
         '"$http_user_agent"'
         'rt=$request_time uct="$upstream_connect_time" uht="$upstream_header_time" urt="$upstream_response_time"';

    access_log  logs/access.log  upstream_time;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    server {
        listen       8070;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }


    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}
    
    upstream backend {
        ip_hash;
        server 2.2.2.2:18083;
    }



    # HTTPS server
    #
    server {
        listen       9898 ssl;
        server_name  2.2.2.2;

        ssl_certificate      C:/certs/ngix.crt;
        ssl_certificate_key  C:/certs/ngix.key;

        ssl_session_cache    shared:SSL:1m;
        ssl_session_timeout  5m;
        
        proxy_ssl_trusted_certificate C:/certs/cert.pem;
        proxy_ssl_certificate C:/certs/cert.pem;
        proxy_ssl_certificate_key C:/certs/cert.key;
    
       #proxy_ssl_verify       on;
       #proxy_ssl_verify_depth 2;
       #proxy_ssl off;

        
        ssl_prefer_server_ciphers  on;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS;
        #add_header Access-Control-Allow-Origin *;

        location / {
        
            add_header 'Access-Control-Allow-Origin' '*' always;
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
            add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
            add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
        
            #proxy_set_header Access-Control-Allow-Origin *;        
            #proxy_set_header Origin 'https://localhost:19093';
            #proxy_set_header X-SSL-CERT $ssl_client_escaped_cert;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header Host $http_host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Host $proxy_add_x_forwarded_for;
            proxy_set_header  Cookie $http_cookie;
            proxy_pass https://backend;
            
            
               
        }

    }

}
可能的成因分析
  • X-Forwarded-Host配置错误:配置中proxy_set_header X-Forwarded-Host $proxy_add_x_forwarded_for;明显有误,X-Forwarded-Host应设置为请求的主机名(如$host或$http_host),而非转发IP列表。这个错误会导致后端SpringBoot服务无法正确解析请求上下文,返回400错误给Nginx,最终传递给客户端。

  • 请求格式不规范:400错误本质是请求不符合HTTP协议规范。该异常API可能包含特殊字符、过长的单个请求头字段、Content-Type与请求体不匹配等问题。尽管配置了large_client_header_buffers 16 128k,但如果存在单个header超过128k的场景,仍会触发400。

  • CORS预检不匹配:如果该API使用了Access-Control-Allow-Methods未包含的HTTP方法(如PUT、DELETE),Angular发起的OPTIONS预检请求会被Nginx或后端拒绝,返回400错误。

  • Cookie传递异常:proxy_set_header Cookie $http_cookie;可能传递了格式异常的Cookie,若该API的Cookie包含特殊字符或过长内容,会导致Nginx或后端解析失败,触发400。

排查建议
  1. 修正X-Forwarded-Host配置,改为:

    proxy_set_header X-Forwarded-Host $host;
    
  2. 扩展access.log的日志格式,添加请求头和请求体相关信息,方便定位异常请求细节:

    log_format upstream_time '$remote_addr - $remote_user [$time_local] '
           '"$request" $status $body_bytes_sent '
           '"$http_user_agent"'
           'rt=$request_time uct="$upstream_connect_time" uht="$upstream_header_time" urt="$upstream_response_time"'
           'headers="$http_all_headers"';
    
  3. 对比异常API与正常API的请求方法、请求头、请求体差异,重点检查Content-Type、特殊参数、Cookie内容。

  4. 临时扩展Access-Control-Allow-Methods包含所有可能用到的HTTP方法(如GET, POST, OPTIONS, PUT, DELETE),测试是否为CORS预检导致的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 07:22:26