源本科技 | 码上会

Nginx 跨域 CORS 配置

2026/05/19
1
0

引言

在现代 Web 开发中,跨域资源共享(CORS)是前端与后端联调时最常见的问题。该问题由浏览器的同源策略安全机制引发,Nginx 作为反向代理服务器,可通过配置 HTTP 响应头快速、优雅地解决跨域问题,无需修改后端业务代码,是生产环境的最优解决方案。

同源策略

同源策略是浏览器内置的核心安全机制,用于限制不同源之间的资源交互,防范 XSS、CSRF 等攻击。

同源判定规则

两个地址满足 协议 + 域名 + 端口号 完全一致,才属于同源;任意一项不同,均判定为跨域。

同源策略限制范围

  • 禁止跨域操作 DOM 元素

  • 禁止跨域发送 Ajax / Fetch 请求

  • 禁止跨域访问 Cookie、LocalStorage 等客户端存储数据

跨域问题演示

当前端页面与后端接口的源不一致时,浏览器会拦截请求并抛出跨域报错。

前端测试代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>跨域测试</title>
</head>
<body>
    <div>Nginx Response: <span id="message"></span></div>
    <script>
        // 跨域请求后端接口
        fetch('http://192.168.60.139/hi')
            .then(res => res.text())
            .then(data => document.getElementById('message').innerHTML = data)
            .catch(err => console.error('跨域错误:', err));
    </script>
</body>
</html>

Nginx 解决跨域

Nginx 通过在响应中添加 CORS 标准 HTTP 头 解决跨域,修复原文档关键缺陷add_header 默认仅对 200/204 等状态码生效,必须添加 always 参数,确保 4xx/5xx 异常状态码也能返回跨域头。

基础配置

开发环境,允许所有源

适用于本地开发,简单快捷:

server {
    listen 80;
    server_name your.domain.com;

    location / {
        # 代理转发后端服务
        proxy_pass http://backend_server;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # 核心:允许所有源跨域,always 强制所有状态码生效
        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 * always;

        # 处理 OPTIONS 预检请求
        if ($request_method = OPTIONS) {
            add_header Access-Control-Max-Age 1728000;
            return 204;
        }
    }
}

安全配置

生产环境,指定允许源

生产环境禁止使用 *,存在安全风险,仅允许指定域名跨域:

add_header Access-Control-Allow-Origin "https://www.xxx.com" always;

前端需要传递 Cookie 时,不允许使用 *,必须指定域名:

location / {
    proxy_pass http://backend_server;

    # 允许指定源
    add_header Access-Control-Allow-Origin "https://www.xxx.com" always;
    # 允许携带凭证
    add_header Access-Control-Allow-Credentials true always;
    add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS always;
    add_header Access-Control-Allow-Headers * always;

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

配置参数

  • Access-Control-Allow-Origin:允许跨域的源地址,* 代表所有,生产环境建议指定域名

  • Access-Control-Allow-Methods:允许的跨域请求方法

  • Access-Control-Allow-Headers:允许的自定义请求头

  • Access-Control-Allow-Credentials:是否允许携带 Cookie 等凭证

  • Access-Control-Max-Age:预检请求缓存时间,单位秒,减少重复预检

  • always:强制所有 HTTP 状态码返回响应头(必加

实战示例

后端服务

@RestController
public class HelloController {
    @GetMapping("/hi")
    public String sayHello() {
        return "Hello from Backend!";
    }
}

Nginx 配置

upstream backend_server {
    server 127.0.0.1:8080;
}

server {
    listen 80;
    server_name your.domain.com;

    location / {
        # 反向代理
        proxy_pass http://backend_server;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # CORS 跨域配置
        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 Content-Type,Authorization always;

        # 处理预检请求
        if ($request_method = OPTIONS) {
            add_header Access-Control-Max-Age 86400;
            return 204;
        }
    }
}