跨域问题背景:同源策略与浏览器限制
聊 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 网关的关系最大。前端发请求没问题,但浏览器会检查响应头。如果没有正确的跨域头,它就“截胡”掉返回值,抛出一个错误。
那浏览器到底怎么拦截的?
很多人以为浏览器直接拒绝了网络请求。其实不是。
真实流程是这样的:
- 前端代码发起一个跨域请求(比如 fetch)。
- 浏览器正常发出这个请求,服务器也正常处理并返回数据。
- 浏览器拿到响应后,检查响应头里有没有
Access-Control-Allow-Origin。 - 如果没有,或者值不匹配,浏览器就把响应数据藏起来,不给 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 网关站在中间,既要应对浏览器的安全检查,又要保证加密传输的安全。
咱们这章的核心逻辑,我用一张图串起来:
这张图画的就是整个跨域流程。你看,不管是同源还是跨域,请求最终都到了后端服务器。区别在于:同源请求直接拿到数据,跨域请求则要过浏览器那一关——检查响应头,通不过就直接拦截。
这对我们的加密方案意味着什么?
搞清楚了同源策略,你就知道API 网关的跨域加密方案要解决两个核心问题:
- 允许跨域访问:通过配置 CORS 头,告诉浏览器“这个来源我允许”。
- 保证数据在跨域传输中不被篡改:加密方案要在网关层做好签名、加密,防止中间人攻击。
这两件事缺一不可。只解决跨域不加密,数据裸奔;只加密不解决跨域,前端拿不到数据。所以后面咱们的每一步,都会围绕这两个目标展开。
一个小提醒:同源策略只存在于浏览器。如果是小程序、App 内部发请求,一般不受同源策略限制。咱们这个课程主要讲浏览器端的 Web 场景,但设计 API 网关时也要考虑其他客户端的兼容性。
好了,同源策略和浏览器限制这部分,咱们就聊到这儿。