0

Nginx CORS与反向代理同时配置方法

2026.05.23 | youres | 23次围观

问题背景:为什么CORS和反向代理会冲突

很多开发者在配置Nginx反向代理时,发现跨域请求突然失效了。浏览器控制台抛出Access-Control-Allow-Origin缺失的错误,但明明已经配置了CORS头。

根本原因是:反向代理改变了请求的来源和路径,导致CORS配置被覆盖或失效

场景一:反向代理后端API,前端跨域失败

典型架构:前端(http://localhost:3000) → Nginx反向代理 → 后端API(http://backend:8080)

前端看到的请求目标是/api,但实际访问的是后端服务。此时CORS配置必须放在反向代理的location块中。

正确配置示例

location /api {
    # CORS配置必须放在proxy_pass之前
    add_header 'Access-Control-Allow-Origin' '' always;
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always;
    add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;
    add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
    
    # 处理预检请求
    if ( = 'OPTIONS') {
        add_header 'Access-Control-Allow-Origin' '' always;
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always;
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;
        add_header 'Content-Type' 'text/plain; charset=utf-8' always;
        add_header 'Content-Length' 0 always;
        return 204;
    }
    
    # 反向代理配置
    proxy_pass http://backend:8080;
    proxy_set_header Host System.Management.Automation.Internal.Host.InternalHost;
    proxy_set_header X-Real-IP ;
    proxy_set_header X-Forwarded-For ;
    proxy_set_header X-Forwarded-Proto ;
}

场景二:反向代理多个后端,每个后端的CORS策略不同

实际生产中,一个Nginx可能代理多个后端服务,每个服务的CORS要求不同。此时需要使用map指令动态配置。

基于Origin动态允许跨域

map   {
    default '';
    '~^https?://localhost(:\d+)?$' '';
    '~^https?://(.+\.)?yourdomain\.com$' '';
    '~^https?://(.+\.)?yourdomain\.cn$' '';
}

server {
    listen 80;
    server_name api.yourdomain.com;
    
    location /service-a {
        add_header 'Access-Control-Allow-Origin'  always;
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
        add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type' always;
        
        if ( = 'OPTIONS') {
            add_header 'Access-Control-Allow-Origin'  always;
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
            add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type' always;
            add_header 'Content-Length' 0;
            return 204;
        }
        
        proxy_pass http://service-a:8080;
    }
    
    location /service-b {
        add_header 'Access-Control-Allow-Origin'  always;
        add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
        add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,X-Request-Id' always;
        
        if ( = 'OPTIONS') {
            add_header 'Access-Control-Allow-Origin'  always;
            add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
            add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,X-Request-Id' always;
            add_header 'Content-Length' 0;
            return 204;
        }
        
        proxy_pass http://service-b:8081;
    }
}

场景三:反向代理+认证(Authorization Header)

当前端需要在跨域请求中携带Authorization头时,CORS配置必须显式允许这个头。

location /api {
    add_header 'Access-Control-Allow-Origin' '' always;
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
    add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,X-Request-Id' always;
    add_header 'Access-Control-Allow-Credentials' 'true' always;
    
    if ( = 'OPTIONS') {
        add_header 'Access-Control-Allow-Origin' '' always;
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
        add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,X-Request-Id' always;
        add_header 'Access-Control-Allow-Credentials' 'true' always;
        add_header 'Content-Length' 0;
        return 204;
    }
    
    proxy_pass http://backend:8080;
    proxy_set_header Authorization $http_authorization;
}

关键注意点:当使用Access-Control-Allow-Credentials: true时,Access-Control-Allow-Origin不能是通配符*,必须指定具体的Origin。

常见错误排查

  • 错误1:CORS头配置在server块,但反向代理的location块中没有继承。解决方法:在每个需要CORS的location块中单独配置,或使用include引入公共配置。
  • 错误2add_header指令在if块中失效。这是Nginx已知问题,解决方法:确保在if块内部也写上add_header,或者使用more_set_headers模块。
  • 错误3:反向代理返回的错误响应(如502)没有CORS头。解决方法:使用proxy_intercept_errors on并配置error_page处理。

内链推荐

版权声明

本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论