跨域问题背景:同源策略与浏览器限制

聊 API 网关的跨域加密方案前,咱们得先弄明白一个根本问题——跨域到底是怎么来的?

说白了,罪魁祸首就是浏览器里的 同源策略。我记得刚入行时,第一次遇到跨域报错,抓耳挠腮了半天,心想:“服务器明明返回数据了,怎么前端就是拿不到?” 后来才明白,这不是后端的问题,是浏览器在“作祟”。

什么是同源策略?

同源策略,是浏览器最核心的安全机制之一。它规定:只有“同源”的页面,才能自由读取对方的资源。

那什么叫“同源”?三个东西必须完全一致:

  • 协议(http 还是 https)
  • 域名(example.com 还是 api.example.com)
  • 端口(80 还是 443,或者 8080)

你想想看,只要一个不对,就算“跨域”。

举个具体例子:

页面在 https://www.myapp.com,想请求 https://api.myapp.com/data。域名不同(www 和 api),就是跨域。协议或端口不同也一样。

为什么浏览器要这么干?

没有同源策略,你的网站就是一个筛子。假设你登录了银行网站,同时又打开了一个恶意网站。没同源策略的话,那个恶意网站就能直接发起请求,读取你的银行账户信息。

我在项目中遇到过类似的场景:一个客户的前端应用嵌入了第三方广告脚本,结果那个脚本试图请求客户的内网 API。嗯,幸亏同源策略拦住了,不然数据就泄露了。

所以,同源策略不是找麻烦,而是保护你。

哪些操作受限制?

同源策略主要限制这三类行为:

操作类型 说明 典型案例
DOM 访问 禁止跨域读取另一个页面的 DOM 结构 iframe 里嵌入不同源的页面,无法操作其内容
AJAX 请求 禁止跨域发起 XMLHttpRequest 或 Fetch 前端调用不同源的 API,浏览器阻止读取返回值
Cookie / Storage 读写 禁止跨域读取对方的 Cookie、LocalStorage 不同子域之间无法共享登录态

这里面,AJAX 请求的限制和我们 API 网关的关系最大。前端发请求没问题,但浏览器会检查响应头。如果没有正确的跨域头,它就“截胡”掉返回值,抛出一个错误。

那浏览器到底怎么拦截的?

很多人以为浏览器直接拒绝了网络请求。其实不是。

真实流程是这样的:

  1. 前端代码发起一个跨域请求(比如 fetch)。
  2. 浏览器正常发出这个请求,服务器也正常处理并返回数据。
  3. 浏览器拿到响应后,检查响应头里有没有 Access-Control-Allow-Origin。
  4. 如果没有,或者值不匹配,浏览器就把响应数据藏起来,不给 JS 代码访问。

嗯,这里要注意:请求其实发出去了,服务器也处理了,只是前端拿不到结果。这在排查问题时很容易被忽略。我见过有人查了半天后端日志,发现请求正常返回 200,但前端就是报错,原因就在这里。

避坑指南:我曾经在调试一个跨域接口时,后端告诉我“我看日志你请求成功了,数据都返回了”。我当时就意识到,这不是后端的事,是浏览器的同源策略在搞鬼。所以各位排查跨域问题时,第一反应别是“后端接口写错了”,先看浏览器控制台的 CORS 报错。

复杂请求与简单请求

浏览器对跨域请求还有更细的区分:简单请求和复杂请求。

简单请求只发一次请求就完事。复杂请求则多一步:先发一个 OPTIONS 预检请求,试探一下服务器“你允许我跨域吗?”,服务器同意了,再发真正的请求。

什么样的算简单请求?

  • 方法只限于 GET、HEAD、POST。
  • Content-Type 只限于 application/x-www-form-urlencoded、multipart/form-data、text/plain。
  • 不能带自定义请求头。

其他情况,都算复杂请求。咱们做 API 网关加密方案时,绝大多数场景都是复杂请求,因为我们要加自定义的加密头、认证头。

个人建议:设计 API 网关时,一定要提前配置好 OPTIONS 预检请求的处理。我见过不少团队,上线后发现“怎么接口第一次请求慢”,排查半天才发现是预检请求耗时。合理缓存 OPTIONS 响应,能省不少事。

同源策略和 API 网关的关系

到这里你应该明白了:同源策略是浏览器端的限制,后端服务本身没有跨域的概念。API 网关站在中间,既要应对浏览器的安全检查,又要保证加密传输的安全。

咱们这章的核心逻辑,我用一张图串起来:

同源策略与跨域请求流程 同源策略与跨域请求流程 用户浏览器 同源请求 ✅ 跨域请求 ❌ 后端服务器 浏览器检查响应头 Access-Control-Allow-Origin 允许 ✅ 拦截 ❌ 核心要点 请求已发出,服务器已处理 但浏览器不交出数据

这张图画的就是整个跨域流程。你看,不管是同源还是跨域,请求最终都到了后端服务器。区别在于:同源请求直接拿到数据,跨域请求则要过浏览器那一关——检查响应头,通不过就直接拦截。

这对我们的加密方案意味着什么?

搞清楚了同源策略,你就知道API 网关的跨域加密方案要解决两个核心问题:

  • 允许跨域访问:通过配置 CORS 头,告诉浏览器“这个来源我允许”。
  • 保证数据在跨域传输中不被篡改:加密方案要在网关层做好签名、加密,防止中间人攻击。

这两件事缺一不可。只解决跨域不加密,数据裸奔;只加密不解决跨域,前端拿不到数据。所以后面咱们的每一步,都会围绕这两个目标展开。

一个小提醒:同源策略只存在于浏览器。如果是小程序、App 内部发请求,一般不受同源策略限制。咱们这个课程主要讲浏览器端的 Web 场景,但设计 API 网关时也要考虑其他客户端的兼容性。

好了,同源策略和浏览器限制这部分,咱们就聊到这儿。