在 Nginx 中配置跨域(CORS)是为了解决浏览器基于安全策略阻止跨域请求的问题。以下是针对 Nginx 跨域配置的分步详解,结合实际场景和代码示例:


一、跨域的核心机制与原因

  1. 什么是跨域

    • 浏览器基于同源策略(Same-Origin Policy),禁止页面从不同域名、端口或协议的服务器请求资源。
    • 跨域触发条件:协议、域名、端口任意一个不同(例如http://a.com访问http://b.com)。
  2. 如何解决跨域

    • 后端服务(如 Nginx)返回允许跨域的响应头(CORS Headers),告知浏览器允许哪些源访问资源。

二、Nginx 跨域配置全流程

在 Nginx 中配置跨域,主要通过添加 add_header 指令设置响应头。

1. 基础跨域配置(允许所有来源)

以下配置允许所有来源的跨域请求:

server {
    listen 80;
    server_name example.com;

    location /api/ {
        # 允许所有来源
        add_header 'Access-Control-Allow-Origin' '*';
        
        # 允许的请求方法(GET, POST等)
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
        
        # 允许的请求头(如Content-Type、Authorization等)
        add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With';
        
        # 允许浏览器暴露的响应头(供前端访问)
        add_header 'Access-Control-Expose-Headers' 'Content-Length, Content-Range';

        # 预检请求(OPTIONS)缓存时间(单位:秒)
        add_header 'Access-Control-Max-Age' 1728000;
        
        # 反向代理到后端服务(如Java微服务)
        proxy_pass http://backend-server;
    }
}

2. 允许特定域名访问

如果只允许特定域名跨域(更安全):

add_header 'Access-Control-Allow-Origin' 'https://your-frontend-domain.com';

3. 处理预检请求(OPTIONS)

浏览器在发送复杂请求(如 PUT、自定义头)前会先发送 OPTIONS 预检请求,需单独处理:

location /api/ {
    # ...

    # 处理 OPTIONS 请求
    if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Allow-Origin' 'https://your-frontend-domain.com';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
        add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With';
        add_header 'Access-Control-Max-Age' 1728000;
        # 无需返回任何内容,浏览器只需要头部信息
        return 204;
    }
}

4. 支持携带凭证(Cookies、Credentials)

如果前端需要发送 Cookies 或认证信息,需额外配置 Access-Control-Allow-Credentials,并禁止使用通配符 *

add_header 'Access-Control-Allow-Origin' 'https://your-frontend-domain.com';
add_header 'Access-Control-Allow-Credentials' 'true';

三、配置关键点与注意事项

  1. 安全性问题

    • 生产环境中避免使用Access-Control-Allow-Origin: *,明确指定允许的域名。
    • 对于动态允许多个域名,可通过 Nginx 变量结合map模块实现:
    map $http_origin $cors_origin {
         default "";
         ~^https?://(.*\.)?allowed-domain1.com$ $http_origin;
         ~^https?://(.*\.)?allowed-domain2.com$ $http_origin;
     }
     add_header 'Access-Control-Allow-Origin' $cors_origin;
  2. 缓存优化

    • 预检请求 (OPTIONS) 可通过Access-Control-Max-Age减少频繁请求,节省带宽。
  3. 常见错误排查

    • 头部顺序问题:确保在返回非200状态码(如204)时仍能添加头部。
    • 配置覆盖问题:若 Nginx 的父级块(如http)已定义add_header,子级块的配置会覆盖父级。使用always关键字强制添加头部:
    add_header 'Access-Control-Allow-Origin' 'https://example.com' always;
  4. 日志调试:查看 access.logerror.log 检查配置是否生效:

    tail -f /var/log/nginx/access.log

四、实际场景案例

场景 1:前后端分离项目接口代理

前端运行在 http://localhost:3000,通过 Nginx 代理后端 http://localhost:8080 的 API:

server {
    listen 80;
    server_name api.example.com;

    location / {
        add_header 'Access-Control-Allow-Origin' 'http://localhost:3000' always;
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
        add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type' always;

        if ($request_method = 'OPTIONS') {
            return 204;
        }

        proxy_pass http://localhost:8080;
    }
}

场景 2:动态允许多个域名

白名单域名:example.comtest.com

map $http_origin $allowed_origin {
    default "";
    ~^https?://(.*\.)?(example\.com|test\.com)$ $http_origin;
}

server {
    location /api/ {
        add_header 'Access-Control-Allow-Origin' $allowed_origin always;
        # ...其他配置
    }
}

五、参考资料

  1. Nginx 官方文档

  2. MDN Web(权威的 CORS 机制解释)

  3. GitHub Gist 常见配置模板

  4. Stack Overflow 调试技巧


标签: Nginx, Nginx跨域, 配置跨域, Nginx 配置跨域

添加新评论