news 2026/7/2 1:48:15

聊聊跨域问题

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
聊聊跨域问题

跨域到底该谁管?浏览器、代理与 Gateway CORS

适用:WeekFlow 前后端分离开发(Vite + Gateway + Nginx)
读者:前后端开发、运维


1. 从一个报错说起

前端跑在http://localhost:5173,Gateway 在http://localhost:8080,控制台出现:

Access to fetch at 'http://localhost:8080/api/v1/auth/health' from origin 'http://localhost:5173' has been blocked by CORS policy

后端说:Gateway 加个CorsConfig
前端说:Vite 配个 proxy 不就行了?

两个人都没错,说的不是同一件事。把机制理顺,本地能跑、上线不踩坑、排查能快。


2. 跨域是浏览器的规矩

CORS(Cross-Origin Resource Sharing)不是 Spring、不是 Nginx 发明的业务规则,是浏览器对页面里 JavaScript 的安全限制

浏览器在把响应交给 JS 之前会问:

  1. 页面来源(Origin)和请求 URL 是否同源?
  2. 不同源的话,响应头里有没有「允许这个来源访问」的声明?

同源要求协议、域名、端口三者完全一致:

页面 Origin请求 URL是否跨域
http://localhost:5173http://localhost:8080/api/...是(端口不同)
http://localhost:5173http://127.0.0.1:8080/api/...是(域名不同)
https://weekflow.comhttps://weekflow.com/api/...否(同源)
https://app.weekflow.comhttps://api.weekflow.com/...是(子域不同)

Postman、curl、Feign、Gateway 转发到下游——都不走这套。所以「Postman 能通、浏览器报 CORS」是正常现象。

允许跨域时,服务端需在响应里带上类似头:

Access-Control-Allow-Origin: http://localhost:5173 Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS Access-Control-Allow-Headers: Authorization, Content-Type Access-Control-Allow-Credentials: true

没有这些头,浏览器会拦截,JS 读不到 body。Network 里可能已是 200,但fetch仍会进catch

结论:限制来自浏览器;「允不允许跨」必须由某层 HTTP 服务通过响应头声明。


3. 前端写死后端地址,一定跨域吗?必须要 CorsConfig 吗?

3.1 写死地址 ≠ 一定跨域

跨域看的是页面 Origin 和请求 URL 是否同源,跟 URL 是相对路径还是写死的绝对地址无关。

// 页面在 http://localhost:5173// 情况 A:写死 8080 → 跨域(5173 ≠ 8080)fetch('http://localhost:8080/api/v1/auth/health')// 情况 B:相对路径 + Vite 代理 → 浏览器认为请求发往 5173,同源fetch('/api/v1/auth/health')// 情况 C:写死地址,但页面本身就在 8080 上(不常见)// 例如静态资源也由 Gateway 或 Nginx 同端口提供 → 不跨域fetch('http://localhost:8080/api/v1/auth/health')

环境变量也一样:

// .env: VITE_API_BASE=http://localhost:8080fetch(`${import.meta.env.VITE_API_BASE}/api/v1/auth/health`)

只要浏览器当前页面的 Origin 是5173,请求目标是8080,就是跨域。
写死只是更容易把 host:port 写错成另一个源;用相对路径/api/...则天然跟页面同源。

3.2 跨域了,是否必须要 CorsConfig?

不必须。CorsConfig只是「让 Gateway 在响应里加 CORS 头」这一种做法。

跨域时浏览器要能正常读响应,至少需要下面之一:

方案做法是否需要 Gateway CorsConfig
同源代理(推荐)Vite / Nginx 反代,前端用相对路径不需要
Gateway CORSSpringCorsWebFilter需要(或等价 Java/YAML 配置)
Nginx 层 CORSadd_header Access-Control-*不需要 Gateway 配,Nginx 配
不处理直连跨域 URL,无任何 CORS 头浏览器拦截 JS 读响应

WeekFlow 若采用开发 Vite 代理 + 生产 Nginx 同源反代,前后端约定用/api/...,则Gateway 的CorsConfig可以没有,不影响正常用户访问。

CorsConfig适合这些场景再开:

  • API 独立域名(如api.weekflow.com,页面在app.weekflow.com
  • 多个前端域名共用一个 API
  • 本地有人习惯直连http://localhost:8080调试,且前端仍从 5173 发起请求
  • 第三方浏览器页面调用开放 API

CORS 头只需在一层加(Gateway 或 Nginx 二选一),多层重复可能出 duplicate header,浏览器照样报错。

3.3 跨域但没 CORS 时,后台有没有收到请求?

有可能收到了。CORS 拦的是浏览器是否允许 JS 读响应,不是网络层能不能连上。

典型现象:Network 显示 200,控制台报 CORS,fetch拿不到数据。
所以「接口在 Postman 里是好的」不能证明浏览器场景没问题。


4. 两条解决思路

思路一:同源代理(WeekFlow 推荐)

不让浏览器跨域,把转发放在服务器侧。

本地 — Vite:

// vite.config.tsexportdefaultdefineConfig({server:{proxy:{'/api':{target:'http://localhost:8080',changeOrigin:true,},'/ws':{target:'ws://localhost:8080',ws:true,changeOrigin:true,},},},})
// 前端统一相对路径awaitfetch('/api/v1/auth/health')

生产 — Nginx:

server { listen 443 ssl http2; server_name weekflow.com; location / { root /var/www/weekflow; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://weekflow-gateway: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; } location /ws/ { proxy_pass http://weekflow-gateway:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; } }

页面与 API 在浏览器里都是https://weekflow.com,不触发 CORS。

思路二:显式 CORS

浏览器直连 API 域名,由 Gateway(或 Nginx)返回Access-Control-Allow-*

WeekFlow Gateway 当前实现:weekflow-gateway模块com.weekflow.gateway.config.CorsConfig,允许http://localhost:5173
若团队确定永远走同源代理,该类可删除或注释,并在团队规范里写清楚。


5. 容易踩坑的点

OPTIONS 预检
Authorization、非简单 Content-Type 时,浏览器会先发 OPTIONS。直连跨域 API 时 Gateway 必须正确处理;走同源代理则通常无感。

WebSocket
REST 代理了,/ws/也要单独配(Vitews: true、Nginx Upgrade 头),否则表现为 HTTP 正常、长连接失败。

Credentials
Cookie 方案下Allow-Origin不能为*,须指定具体域名且Allow-Credentials: true。Bearer Token 一般简单些。

开发与生产策略不一致
开发用 proxy、预发却改成https://api.staging.xxx.com直连,联调阶段会突然冒出 CORS。团队应统一:各环境前端 baseURL 怎么配、是否允许写死后端 host。

微服务间调用
Gateway → auth-service、OpenFeign 等不涉及 CORS,仅影响浏览器里的 JS。


6. WeekFlow 团队约定(建议)

  1. 前端请求使用相对路径/api/.../ws/...,环境变量里不要写死后端host:port(除非明确走跨域 + CORS 方案)。
  2. 本地:Vite proxy → Gateway8080
  3. 生产:Nginx 同域名反代 → Gateway。
  4. GatewayCorsConfig:按需启用(API 独立域名或多前端源时再开)。
  5. CORS 只在一层配置,避免 Gateway 与 Nginx 重复。

7. 排查清单

浏览器报 CORS 时,依次确认:

  1. 当前页面 Origin 是什么?(地址栏 + 端口)
  2. 请求完整 URL 是什么?相对路径还是写死的绝对地址?
  3. 中间有没有 Vite / Nginx 代理?代理规则是否覆盖该路径?
  4. 若是跨域直连,Gateway 或 Nginx 是否返回了 CORS 头?(看 Response Headers)
  5. 是否只有浏览器失败、Postman 正常?(是则基本可断定 CORS 问题)

8. 相关代码与文档

位置
Gateway CORS(可选)weekflow-gateway/.../config/CorsConfig.java
Gateway 路由weekflow-gateway/src/main/resources/application.yml
开发计划 Step 1.3.4docs/architecture/03-开发计划.md

9. 一句话总结

  • 写死后端地址:只有页面 Origin 与目标 URL 不同源时才跨域;写死8080而页面在5173就会跨域。
  • CorsConfig:不是必选项,是「跨域直连 API」时的一种解法;同源代理方案下可以不要
  • 团队真正要对齐的是:前端 URL 怎么写、代理在哪一层、什么场景才开 CORS
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/2 1:46:37

SSE客户端C++实现(使用libcurl)

SSE协议 的全称是 Server-Sent Events(服务器发送事件),本质是基于 HTTP 协议的 “单向实时推送技术”——只有服务器能主动给客户端发消息,除了发送订阅请求外,客户端只能接收数据。SSE消息是纯文本格式,S…

作者头像 李华
网站建设 2026/7/2 1:46:10

Qt问题记录002:QMap的erase陷阱,正常运行与调试模式结果不同

Qt的QMap循环删除元素(erase),在运行时正常,在调试模式下报错,提供解决代码。关键词:QMap、erase、迭代器、遍历与删除问题描述:在使用 Qt 的QMap 容器时,尝试在遍历过程中删除元素&…

作者头像 李华
网站建设 2026/7/2 1:42:03

大模型评测与AI产品质量保障:第7篇 机器学习的三种学习范式

IT策士 10余年一线大厂经验,专注大模型测试、AI产品质量保障与职场进阶。我会在各个平台持续发布最新文章,助你少走弯路。 上一篇文章我们拆解了AI的六块技术拼图。但无论哪块拼图,背后驱动模型学习的都是三种核心范式——有监督学习、无监督…

作者头像 李华
网站建设 2026/7/2 1:39:44

turn_on_wheeltec_robot.launch

<launch><!-- Arguments参数 --><arg name"lidar_is_cx" default"false"/><arg name"car_mode" default"mini_4wd" doc"opt: mini_akm,senior_akm,top_akm_bs,top_akm_dl,mini_mec,senior_mec_bs,senior_m…

作者头像 李华
网站建设 2026/7/2 1:37:44

Skill安全系列之Skill基础

前言 在总结Skill中的相关风险前&#xff0c;我们先通过一篇的内容来看下什么是Skill&#xff0c;对其有一个初步的认识。 什么是Skill Skill翻译为技能的意思&#xff0c;在AI邻域中&#xff0c;Skill就是一个技能&#xff0c;比如给Agent一个A技能&#xff0c;那我们就需要拥…

作者头像 李华