Nginx反向代理解决跨域问题详解

Nginx反向代理解决跨域问题详解

核心原理

Nginx反向代理解决跨域的核心思路是让客户端请求同域名下的接口,由Nginx将请求转发到目标服务器,从而规避浏览器的同源策略限制。

复制代码
客户端(同源:www.domain.com)
        ↓
    Nginx(同源:www.domain.com)
        ↓
目标服务器(跨域:api.external.com)

完整配置与代码示例

基本反向代理配置

nginx 复制代码
# /etc/nginx/conf.d/default.conf

server {
    listen 80;
    server_name mydomain.com;  # 前端域名
    
    # 前端静态资源
    location / {
        root /usr/share/nginx/html;
        index index.html;
    }
    
    # 接口代理配置
    location /api {
        # 后端实际地址(跨域的目标服务器)
        proxy_pass http://api.external.com;
        
        # 设置必要的请求头
        proxy_set_header Host $proxy_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;
        
        # CORS支持(可选)
        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' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization' always;
        add_header 'Access-Control-Allow-Credentials' 'true' always;
        
        # 处理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

    nginx 复制代码
    location /api {
        proxy_pass http://api.external.com;
    }
    • 所有以/api开头的请求都会被转发到http://api.external.com
  2. 请求头保留

    nginx 复制代码
    proxy_set_header Host $proxy_host;      # 保留原始主机头
    proxy_set_header X-Real-IP $remote_addr; # 保留客户端真实IP
  3. CORS支持

    nginx 复制代码
    add_header 'Access-Control-Allow-Origin' '*' always;
    add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
    • 直接从Nginx层支持CORS,后端服务不需要额外处理
  4. OPTIONS请求处理

    nginx 复制代码
    if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Max-Age' 1728000;
        # ...
        return 204;
    }
    • 直接响应预检请求,减轻后端服务器压力

常见场景定制配置

场景1:URL重写(删除API前缀)
nginx 复制代码
location /api {
    # 重写路径:移除/api前缀
    rewrite ^/api/(.*)$ /$1 break;
    proxy_pass http://api.external.com;
}
场景2:添加API前缀
nginx 复制代码
location /user-service {
    # 添加/api前缀
    rewrite ^/user-service/(.*)$ /api/$1 break;
    proxy_pass http://api.external.com;
}
场景3:负载均衡
nginx 复制代码
upstream backend {
    server backend1.example.com:8080 weight=3;  # 权重
    server backend2.example.com:8081;
    server backup.example.com:8082 backup;       # 备用服务器
}

location /api {
    proxy_pass http://backend;  # 使用负载均衡器
    proxy_set_header Host $host;
}
场景4:WebSocket支持
nginx 复制代码
location /socket {
    proxy_pass http://ws-server.com;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
}

前端代码示例

javascript 复制代码
// 请求代理路径(不再需要直接访问跨域地址)
const API_BASE = '/api'; // 与Nginx配置中的location匹配

// GET请求示例
async function getData() {
  try {
    const response = await fetch(`${API_BASE}/data`, {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json'
      }
    });
    return await response.json();
  } catch (error) {
    console.error('Error fetching data:', error);
  }
}

// POST请求示例
async function postData(data) {
  try {
    const response = await fetch(`${API_BASE}/save`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${token}`
      },
      body: JSON.stringify(data)
    });
    return await response.json();
  } catch (error) {
    console.error('Error posting data:', error);
  }
}

完整操作流程

  1. 安装Nginx

    bash 复制代码
    # Ubuntu/Debian
    sudo apt update
    sudo apt install nginx
    
    # CentOS/RHEL
    sudo yum install epel-release
    sudo yum install nginx
  2. 编辑配置文件

    bash 复制代码
    sudo nano /etc/nginx/conf.d/default.conf

    添加上面的代理配置

  3. 测试配置

    bash 复制代码
    sudo nginx -t

    输出 syntax is oktest is successful 表示配置正确

  4. 重启Nginx

    bash 复制代码
    sudo systemctl restart nginx
    # 或
    sudo service nginx restart
  5. 部署前端项目

    bash 复制代码
    # 将前端构建文件放入指定目录
    sudo cp -R /path/to/dist /usr/share/nginx/html
  6. 验证访问

    访问 http://your-domain.com 应该加载前端页面,所有API请求自动代理到目标服务

优势对比

方案 是否需要修改代码 安全性 性能影响 多服务支持
Nginx反向代理 ⭐⭐⭐⭐⭐ 几乎没有 ⭐⭐⭐⭐⭐
CORS ⭐⭐⭐⭐ 中等 ⭐⭐
JSONP
Webpack代理 ✘ (仅开发) ⭐⭐ 低(开发) ⭐⭐

注意事项

  1. 路径匹配

    • 确保location指令的路径匹配模式与前端请求一致
    • 使用正则表达式处理复杂的URL模式
  2. 日志调试

    nginx 复制代码
    location /api {
        proxy_pass http://api.external.com;
        access_log /var/log/nginx/api-access.log;
        error_log /var/log/nginx/api-error.log;
    }
  3. 超时设置

    nginx 复制代码
    proxy_connect_timeout 60s;   # 连接超时
    proxy_send_timeout 60s;       # 发送超时
    proxy_read_timeout 180s;      # 读取超时
  4. Cookie传递

    nginx 复制代码
    proxy_cookie_domain api.external.com mydomain.com;
    proxy_cookie_path / /api/;
  5. 安全限制

    • 避免完全开放的跨域(Access-Control-Allow-Origin: *)
    • 建议使用具体的域名白名单

Nginx反向代理是当前解决跨域问题最成熟、稳定、高性能的解决方案,特别适合生产环境使用,既能解决跨域问题,又能实现负载均衡、安全防护等额外好处。

相关推荐
egoist202313 分钟前
【Linux仓库】进程优先级及进程调度【进程·肆】
linux·运维·服务器·进程切换·进程调度·进程优先级·大o1调度
格调UI成品2 小时前
预警系统安全体系构建:数据加密、权限分级与误报过滤方案
大数据·运维·网络·数据库·安全·预警
xuanzdhc6 小时前
Linux 基础IO
linux·运维·服务器
愚润求学6 小时前
【Linux】网络基础
linux·运维·网络
小和尚同志7 小时前
29.4k!使用 1Panel 来管理你的服务器吧
linux·运维
就叫飞六吧9 天前
基于keepalived、vip实现高可用nginx (centos)
python·nginx·centos
小米里的大麦9 天前
014 Linux 2.6内核进程调度队列(了解)
linux·运维·驱动开发
程序员的世界你不懂9 天前
Appium+python自动化(三十)yaml配置数据隔离
运维·appium·自动化
算法练习生9 天前
Linux文件元信息完全指南:权限、链接与时间属性
linux·运维·服务器
浩浩测试一下9 天前
渗透测试指南(CS&&MSF):Windows 与 Linux 系统中的日志与文件痕迹清理
linux·运维·windows·安全·web安全·网络安全·系统安全