当前位置: 首页 > news >正文

Kubernetes 双层 Nginx 容器环境下的 CORS 问题及解决方案(极端情况)

在实际开发和运维中,CORS(跨源资源共享)是前端调用后端接口时最常遇到的安全策略问题之一。大多数情况下,只需在后端服务器上正确配置 Access-Control-Allow-Origin 即可。

但本人遇到了 双层 Nginx 代理极端 情况(K8s 上 Nginx 容器代理后,再由 Nginx 代理出来),常规修改方法往往失效,以下是原理分析以及解决方案。


一、背景

我所在的环境中,前端和后端均部署在 Kubernetes 上:

  • 前端 Nginx:Nginx 容器,把前端文件代理(第一次代理)出来,但用户无法直接访问(不允许)K8s 的容器服务,所以又通过 外部 Nginx(第二次代理)出来。
  • 后端 API:Python 容器,通过 python 启动一个 API 服务(占用一个端口),再通过 外部 Nginx 代理出来,由 前端 Nginx 访问。

访问流程大致如下:

浏览器 → 前端 Nginx → 后端 API → Python 服务

在本地开发环境中,使用 前端 Nginx image,直接部署映射端口出来,且不调整 后端 API 的情况下,直接修改 后端 API Nginx 的 CORS 配置即可正常工作:

不修改会有跨域问题

# Nginx 配置文件
server {listen 80;server_name api.example.com;location / {# 允许特定的域名 # 即:返回的包头添加了 Access-Control-Allow-Origin:http://www.example.com 信息# 当 http://www.example.com 与当前页面访问的域名(http)匹配上就正常add_header 'Access-Control-Allow-Origin' 'http://www.example.com';# 允许的 HTTP 方法add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';# 允许的请求头add_header 'Access-Control-Allow-Headers' 'Origin, Content-Type, Accept, Authorization';# 允许 Cookie 传递add_header 'Access-Control-Allow-Credentials' 'true';# 处理复杂请求的预检 OPTIONS 请求if ($request_method = 'OPTIONS') {add_header 'Access-Control-Allow-Origin' 'http://www.example.com';add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';add_header 'Access-Control-Allow-Headers' 'Origin, Content-Type, Accept, Authorization';add_header 'Access-Control-Allow-Credentials' 'true';return 204;}proxy_pass http://backend_server;}
}

http://www.example.com 部分改成 宿主机IP:映射端口 即可。

此部分参考,博文:
解决跨域请求的终极指南:从 CORS 到 Nginx 配置,掌握关键技巧!

但把 前端服务 重新部署到到生产环境 Kubernetes 上,经过两层 Nginx 代理后,浏览器报错:

CORS 头 'Access-Control-Allow-Origin' 不匹配 'http://www.example.com, http://www.example.com'

明显看到 响应头重复,导致浏览器拒绝访问。


二、问题分析

1. CORS 的基本原理

CORS 是浏览器的一种安全策略,用来限制网页从一个源发起对另一个源的请求。浏览器检查响应头:

  • Access-Control-Allow-Origin 必须包含当前网页的 Origin。
  • 复杂请求会先发送 OPTIONS 预检请求。

⚠️ 关键点:浏览器只关心 最终返回给它的响应头
内层代理返回的头,如果被外层代理覆盖或拼接,就会失效。

2. 双层代理带来的特殊情况

前端服务两层 Nginx:

  1. 内层 Nginx(第一层)返回了 Access-Control-Allow-Origin: *
  2. 外层 Nginx(第二层)默认也可能添加或拼接了 CORS 头。

最终浏览器看到的响应头可能是:

Access-Control-Allow-Origin: http://www.example.com, *

很明显这个 CORS 头就是不合法的,这样 API 后端无论写什么地址都匹配不上了。


三、解决方案

1. 原则

CORS 头必须由最外层 Nginx 返回,内层 Nginx 不再添加。

  • 内层 Nginx 只做纯粹的反向代理,不加 CORS。
  • 外层 Nginx 根据浏览器 Origin 动态返回 Access-Control-Allow-Origin
  • 支持 OPTIONS 预检请求返回 204。

2. 实现方案

前端服务内部 Nginx(第一层Nginx)原本就没加 CORS 头,只是单纯代理出来,就不修改了。

在外部的Nginx上(第二层)nginx.conf 配置文件下修改。

在 http 块定义 map(server 外部)

map $http_origin $allow_origin {default "";"~^https?://www\.example\.com$" $http_origin;
}

外层 Nginx(前端)配置

server {listen 80;server_name www.example.com;location / {# 处理预检请求 OPTIONSif ($request_method = OPTIONS) {add_header Access-Control-Allow-Origin $allow_origin always;add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE" always;add_header Access-Control-Allow-Headers "Origin, Content-Type, Accept, Authorization" always;add_header Access-Control-Max-Age 86400 always;return 204;}# 正常请求加 CORS 头add_header Access-Control-Allow-Origin $allow_origin always;add_header Access-Control-Allow-Credentials true always;proxy_pass http://example.swtxt.svc.cluster.local:8088;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}
}

内层 Nginx(API 后端)配置

server {listen 80;server_name www.exampleapi.com;location / {proxy_pass http://example.swtxt.svc.cluster.local:8000;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}
}

3. 关键点

  • map 必须在 server 外部定义
  • $allow_origin 保证只返回一个合法 Origin
  • always 确保即使 4xx/5xx 响应也带头
  • 内层 Nginx 不要重复添加 CORS

然后浏览器访问测试,是OK的,没有跨域问题了。


四、总结

做到这里,虽然都解决跨域问题了,但还会有个疑问:

为什么“前端只一层 nginx 时 CORS 要配置在后端”,
而“前端两层 nginx 时 CORS 要配置最外层前端 nginx”?
浏览器不是都只看前端域名吗??

前端只 一层 Nginx

浏览器 (域名:www.example.com)↓ 反向代理
前端 Nginx↓
后端 API 服务

浏览器 来说:

网络流向:浏览器 → 后端 API
若前后端不分离(不跨域),浏览器 → 前端 Nginx → 后端 API(浏览器对后端不可见)

前端和后端都是“公开的独立域名”
所以 Cross-Domain = 前端域名访问后端域名

因此 后端必须允许前端域名 CORS

Access-Control-Allow-Origin: https://www.example.com
配置位置原因
后端 Nginx 添加 CORS因为前端域名直接请求到 API 域名 → 后端必须允许

前端有 两层 Nginx(外层一层,内层一层)

浏览器 (域名:www.example.com)↓
外层前端 Nginx (公网)↓
内层前端/后端 Nginx (集群内)↓
后端 API 服务

注意这里:
➡ 浏览器 再也访问不到内部 Nginx 和后端 API
➡ 请求永远到不了内部那一层就已被外层拦截

浏览器看到的世界:

浏览器 → www.example.com (只经过外层 Nginx)

浏览器不知道还有反向代理、内网服务
所有跨域判断都发生在和浏览器直接通信的那一层
也就是:外层前端 Nginx

📌 所以:

配置位置原因
外层前端 Nginx 添加 CORS因为它是浏览器的唯一交互对象,必须允许请求通过

内部 Nginx 和 API 不需要设置 CORS
因为浏览器永远看不到 + 不会触发跨域检查

用一句话总结

跨域检查(CORS)只有在浏览器环境中才会触发。

浏览器只会对它“看得到的那一跳”做跨域检查。
看不到的代理层不需要设置 CORS。

哪一层返回响应给浏览器,CORS 就必须在哪一层配置。

当然,跨域 情况遇到本来就比较少了,现在双 Nginx跨域 极端情况下,就更少见了,这么搞一次,可以对前后端网络流量、CORS 有更清晰的认知。

http://www.dtcms.com/a/552775.html

相关文章:

  • Kimi发布新一代注意力架构!线性注意力实现75% KV缓存减少、6倍解码速度提升
  • 做电子商务系统网站建设wordpress图片加水印
  • 电机参数标幺化与定点计算在整数MCU上的实现
  • Rust开发之错误处理与日志记录结合(log crate使用)
  • 2025年11月1日(星期六)骑行笔架山
  • opencv 学习: 03 初识 cv:Mat
  • 数据结构(c++版):邻接矩阵的实现
  • 在华为TaiShan 200系列服务器基于CentOS 7.6/7.7创建虚拟机
  • Parallels Desktop 26.1.1 for Mac 秋叶QiuChenly中文解锁直装版,最好用的macOS虚拟机
  • Linux chmod权限速成指南
  • 企业网站建设市场的另一面写字就能赚钱做网站
  • 【已解决】解决CondaVerificationError:PyTorch安装包损坏问题
  • UI引擎里AceAbility::OnStart函数1
  • 卸载工具uninstall tool下载安装教程(附安装包)绿色版
  • Bug: 升级内核后有线网络无法使用
  • 帕金森症手绘图像分类数据集
  • 本地生活曝光缺失?GEO语义锚点来救场
  • Rust开发之Result枚举与?运算符简化错误传播
  • Rust专项——其他集合类型详解:BTreeMap、VecDeque、BinaryHeap
  • 软件开发模式架构选择
  • 网站开发设计注册注册小程序
  • Git命令(三)
  • Spring Security 新手学习教程
  • 72.是否可以把所有Bean都通过Spring容器来管
  • DevExpress WPF中文教程:Data Grid - 如何使用虚拟源?(四)
  • 车载软件需求开发与管理 --- 需求收集与整理
  • [linux仓库]线程控制[线程·叁]
  • 从工行“余额归零”事件看CAP定理:当金融系统在一致性与可用性之间做出选择
  • Java的stream使用方案
  • 给网站做视频怎么赚钱电影网站系统源码