Nginx 反向代理后端接口,一步步解决跨域冲突、预检报错问题

前言

日常开发部署后端服务时,常会遇到一个高频难题:前端多域名访问后端接口、Nginx 反向代理 + 后端自带跨域配置,双重冲突导致跨域报错、OPTIONS 预检请求失败、接口请求异常。

前段时间部署项目,后端部署在本地127.0.0.1:8270,前端对接多个业务域名,包含test1.comtest2.com、test3.com等。

初期出现严重跨域问题:

  1. 后端自带跨域响应头,+ Nginx 额外配置跨域,出现重复跨域头
  2. 多域名访问,跨域白域无法统一管理;
  3. 前端 OPTIONS 预检请求无响应,接口直接拦截;
  4. 跨域证书、请求头权限受限,POST、PUT 等请求报错。

本文完整记录,我如何通过 Nginx 配置优化,一站式彻底解决多域名跨域、重复请求头、预检失败全流程问题。

一、问题根源分析

1. 核心矛盾

后端服务本身配置了跨域响应头,前端通过 Nginx 反向代理访问,若 Nginx 再叠加跨域配置,会造成:

  • Access-Control-Allow-Origin 重复报错;
  • 多域名白名单无法统一管控;
  • 浏览器跨域校验规则冲突。

2. 特殊问题

现代前端请求中,POSTPUTDELETE、带Content-TypeAuthorization请求头的接口,会触发 OPTIONS 预检请求

3. 业务需求

项目需要支持多个前端域名访问:

二、解决方案整体思路

采用Nginx 全局接管跨域方案,核心思路四步走:

  1. 屏蔽后端跨域头:禁止后端返回的跨域相关头信息,避免重复冲突;
  2. 配置多域名白名单:正则匹配合法域名,动态配置跨域来源;
  3. 拦截 OPTIONS 预检请求:Nginx 直接返回 204 状态码 + 标准跨域头,不转发后端;
  4. 常规请求统一附加跨域头:所有正常接口请求,统一添加合规跨域配置。

全程不修改后端代码,纯 Nginx 配置优化,零业务改动、低风险、一键生效

三、分步落地配置优化

第一步:屏蔽后端原生跨域响应头

问题核心源头就是「后端 + Nginx 双重跨域」,优先禁用后端所有跨域相关头,杜绝冲突。

使用proxy_hide_header指令,屏蔽后端返回的跨域关键头:

nginx

ini 复制代码
# 1. 先统一隐藏后端所有跨域头(解决重复冲突问题)
proxy_hide_header Access-Control-Allow-Origin;
proxy_hide_header Access-Control-Allow-Methods;
proxy_hide_header Access-Control-Allow-Headers;
proxy_hide_header Access-Control-Allow-Credentials;

配置作用:后端无论如何配置跨域,都不会传递到前端,所有跨域逻辑全权交给 Nginx 控制

第二步:配置多域名跨域白名单

采用$http_origin获取访问来源,通过正则匹配合法域名,动态赋值跨域来源,支持主域名 + www 子域名。

覆盖当前所有业务域名:

nginx

bash 复制代码
# 2. 配置多域名白名单,动态匹配合法来源
set $cors_origin "";
if ($http_origin ~* "^https://(www\.)?test1\.com$") {
    set $cors_origin $http_origin;
}
if ($http_origin ~* "^https://(www\.)?test2\.com$") {
    set $cors_origin $http_origin;
}
if ($http_origin ~* "^https://(www\.)?test3\.com$") {
    set $cors_origin $http_origin;
}
  • 正则(www\.)?:兼容有无 www 前缀;
  • 仅匹配合法域名,非法来源不赋值,杜绝跨域漏洞;
  • 动态赋值,符合浏览器跨域同源策略要求。

第三步:特殊处理 OPTIONS 预检请求

前端复杂请求必先发送 OPTIONS 预检,后端无对应处理逻辑,极易报错。

解决方案:Nginx 直接拦截 OPTIONS 请求,返回 204 无内容状态码,并附加完整跨域头,无需转发后端:

nginx

ini 复制代码
# 3. 拦截OPTIONS预检请求,直接返回204状态码
if ($request_method = OPTIONS) {
    add_header Access-Control-Allow-Origin $cors_origin always;
    add_header Access-Control-Allow-Methods "GET,POST,OPTIONS,PUT,DELETE" always;
    add_header Access-Control-Allow-Headers "Content-Type,Authorization" always;
    add_header Access-Control-Allow-Credentials "true" always;
    return 204;
}
  • 配置全量请求方式:GET/POST/PUT/DELETE/OPTIONS;
  • 放行常用请求头:格式头、授权头;
  • 开启跨域凭证支持,适配登录鉴权场景。

第四步:常规接口统一附加跨域头

除预检请求外,所有 GET、POST 等正常业务请求,统一添加跨域响应头,保证接口正常访问:

nginx

bash 复制代码
# 4. 正常业务请求,统一添加跨域配置
add_header Access-Control-Allow-Origin $cors_origin always;
add_header Access-Control-Allow-Methods "GET,POST,OPTIONS,PUT,DELETE" always;
add_header Access-Control-Allow-Headers "Content-Type,Authorization" always;
add_header Access-Control-Allow-Credentials "true" always;

always关键字至关重要:无论响应状态码 200/400/500,都强制携带跨域头,避免异常接口跨域失效。

第五步:保留原有反向代理核心配置

跨域配置完全独立隔离,原有反向代理、IP 转发、超时、WebSocket 升级等配置完全保留,不影响原有业务运行:

nginx

ini 复制代码
# 原有反向代理配置,完全保留无修改
proxy_pass http://127.0.0.1:8270;
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 REMOTE-HOST $remote_addr;
add_header X-Cache $upstream_cache_status;
proxy_set_header X-Host $host:$server_port;
proxy_set_header X-Scheme $scheme;
proxy_connect_timeout 30s;
proxy_read_timeout 86400s;
proxy_send_timeout 30s;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

四、完整最终 Nginx 配置

bash 复制代码
location / {
    # 1. 先统一隐藏后端所有跨域头(解决重复冲突问题)
    proxy_hide_header Access-Control-Allow-Origin;
    proxy_hide_header Access-Control-Allow-Methods;
    proxy_hide_header Access-Control-Allow-Headers;
    proxy_hide_header Access-Control-Allow-Credentials;

    # 2. 配置多域名白名单,动态匹配合法来源
    set $cors_origin "";
    if ($http_origin ~* "^https://(www\.)?test1\.com$") {
        set $cors_origin $http_origin;
    }
    if ($http_origin ~* "^https://(www\.)?test2\.com$") {
        set $cors_origin $http_origin;
    }
    if ($http_origin ~* "^https://(www\.)?test3\.com$") {
        set $cors_origin $http_origin;
    }

    # 3. 拦截OPTIONS预检请求,直接返回204状态码
    if ($request_method = OPTIONS) {
        add_header Access-Control-Allow-Origin $cors_origin always;
        add_header Access-Control-Allow-Methods "GET,POST,OPTIONS,PUT,DELETE" always;
        add_header Access-Control-Allow-Headers "Content-Type,Authorization" always;
        add_header Access-Control-Allow-Credentials "true" always;
        return 204;
    }

    # 4. 正常业务请求,统一添加跨域配置
    add_header Access-Control-Allow-Origin $cors_origin always;
    add_header Access-Control-Allow-Methods "GET,POST,OPTIONS,PUT,DELETE" always;
    add_header Access-Control-Allow-Headers "Content-Type,Authorization" always;
    add_header Access-Control-Allow-Credentials "true" always;

    # 原有反向代理核心配置,无任何修改
    proxy_pass http://127.0.0.1:8270;
    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 REMOTE-HOST $remote_addr;
    add_header X-Cache $upstream_cache_status;
    proxy_set_header X-Host $host:$server_port;
    proxy_set_header X-Scheme $scheme;
    proxy_connect_timeout 30s;
    proxy_read_timeout 86400s;
    proxy_send_timeout 30s;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

五、配置校验与上线步骤

  1. 校验 Nginx 语法

    nginx -t

若无报错,说明配置语法无误。

  1. 平滑重载生效

    systemctl reload nginx

平滑重启,不中断线上业务。

相关推荐
星辰徐哥14 小时前
Spring Boot 微服务架构设计与实现
spring boot·后端·微服务
星辰徐哥14 小时前
Spring Boot 数据导入导出与报表生成
spring boot·后端·ui
明夜之约14 小时前
Spring Boot 自动装配源码
java·spring boot·后端
Leaton Lee14 小时前
Spring Boot分层架构详解:从Controller到Service再到Mapper的完整流程
java·spring boot·后端·架构
Micro麦可乐14 小时前
Spring Boot 实战:从零设计一个短链系统(含完整代码与数据库设计)
数据库·spring boot·后端·哈希算法·雪花算法·短链系统
Jinkxs14 小时前
Resilience4j- 与 Spring Boot 快速集成:自动配置与基础注解使用
java·spring boot·后端
毕设源码_郑学姐14 小时前
计算机毕业设计springboot网络相册设计与实现 基于Spring Boot框架的在线相册管理系统开发与应用 Spring Boot驱动的网络影集设计与实践
spring boot·后端·课程设计
辣机小司14 小时前
【踩坑记录:Spring Boot 配置文件读取值不一致?警惕 YAML 的“八进制陷阱”与 SnakeYAML 版本之谜】
java·spring boot·后端·yaml·踩坑记录
码农阿豪14 小时前
从零到一:Spring Boot快速接入金仓数据库实战
数据库·spring boot·后端
追逐时光者14 小时前
一个基于 .NET 与 Avalonia 构建、面向 TrinityCore 的开源 WoW 数据库编辑器
后端·.net