插件窝 干货文章 使用Nginx代理解决跨域问题并传递请求头的完整指南

使用Nginx代理解决跨域问题并传递请求头的完整指南

header Control Access proxy 840    来源:    2025-04-02

使用Nginx代理解决跨域问题并传递请求头的完整指南

跨域问题简介

跨域问题(CORS, Cross-Origin Resource Sharing)是浏览器出于安全考虑实施的同源策略限制。当Web应用尝试从不同域名、协议或端口请求资源时,浏览器会阻止这些请求。

Nginx代理解决方案

Nginx可以作为反向代理服务器,将跨域请求转换为同源请求,从而绕过浏览器的限制。

基础配置示例

server {
    listen 80;
    server_name yourdomain.com;

    location /api/ {
        # 代理到实际的后端服务器
        proxy_pass http://backend-server:8080/;

        # 处理跨域相关头信息
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
        add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With';

        # 预检请求(OPTIONS)处理
        if ($request_method = 'OPTIONS') {
            add_header 'Access-Control-Max-Age' 1728000;
            add_header 'Content-Type' 'text/plain; charset=utf-8';
            add_header 'Content-Length' 0;
            return 204;
        }
    }
}

详细配置说明

1. 代理设置

proxy_pass http://backend-server:8080/;
  • 将请求转发到实际的后端服务
  • 确保结尾的/正确处理URI重写

2. CORS头设置

add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Requested-With';
  • Access-Control-Allow-Origin: 允许的源,*表示所有,生产环境建议指定具体域名
  • Access-Control-Allow-Methods: 允许的HTTP方法
  • Access-Control-Allow-Headers: 允许的请求头

3. 预检请求处理

if ($request_method = 'OPTIONS') {
    add_header 'Access-Control-Max-Age' 1728000;
    add_header 'Content-Type' 'text/plain; charset=utf-8';
    add_header 'Content-Length' 0;
    return 204;
}
  • 处理浏览器发送的OPTIONS预检请求
  • Access-Control-Max-Age指定预检请求的缓存时间(秒)

4. 请求头传递

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
  • 确保原始请求头正确传递到后端服务
  • 特别处理如Authorization等敏感头

高级配置

1. 多域名支持

map $http_origin $cors_origin {
    default "";
    "~^https://domain1.com" "https://domain1.com";
    "~^https://domain2.com" "https://domain2.com";
}

server {
    # ...
    add_header 'Access-Control-Allow-Origin' $cors_origin;
    # ...
}

2. 带Cookie的跨域请求

add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Origin' $http_origin;
  • 需要设置Access-Control-Allow-Credentials: true
  • Access-Control-Allow-Origin不能为*,必须指定具体域名

3. WebSocket代理

location /ws/ {
    proxy_pass http://backend-ws-server;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
}

常见问题解决

1. 请求头未传递

确保添加以下配置:

proxy_pass_request_headers on;

2. 特定头被过滤

显式传递需要的头:

proxy_set_header Authorization $http_authorization;

3. 响应头被覆盖

使用more_set_headers模块(需要安装headers-more模块):

more_set_headers 'Access-Control-Allow-Origin: $http_origin';

4. 大文件上传问题

调整缓冲区大小:

client_max_body_size 100M;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;

完整示例配置

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

    # 全局CORS设置
    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-Expose-Headers' 'Content-Length, Content-Range';

    # API代理
    location /api/ {
        proxy_pass http://backend-server:8080/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # 动态设置允许的源
        if ($http_origin ~* (https?://[^/]*\.yourdomain\.com(:[0-9]+)?$)) {
            add_header 'Access-Control-Allow-Origin' "$http_origin";
            add_header 'Access-Control-Allow-Credentials' 'true';
        }

        # 预检请求处理
        if ($request_method = 'OPTIONS') {
            add_header 'Access-Control-Max-Age' 1728000;
            add_header 'Content-Type' 'text/plain; charset=utf-8';
            add_header 'Content-Length' 0;
            return 204;
        }
    }

    # 静态文件服务
    location / {
        root /var/www/html;
        try_files $uri $uri/ /index.html;
    }
}

测试与验证

  1. 检查Nginx配置语法:
nginx -t
  1. 重载Nginx配置:
nginx -s reload
  1. 使用curl测试:
curl -I -X OPTIONS http://yourdomain.com/api/endpoint
  1. 浏览器开发者工具检查响应头是否符合预期。

安全注意事项

  1. 生产环境不要使用Access-Control-Allow-Origin: *
  2. 限制允许的方法和头,仅开放必要的
  3. 考虑添加速率限制防止滥用
  4. 对敏感操作实施额外的认证和授权检查

通过以上配置,Nginx可以有效地解决跨域问题,同时确保请求头正确传递到后端服务。根据实际需求调整配置参数,平衡功能与安全性。