理解跨域与预检请求:魔法屋与通行证的故事
🌐 理解跨域与预检请求:魔法屋与通行证的故事
前言
你是否在调试前端请求时遇到这样的错误?
Access to fetch at 'https://api.xxx.com/data' from origin 'http://localhost:3000' has been blocked by CORS policy...
这不是代码错了,而是你被浏览器的**“同源策略”**拦住了。要想搞清楚为什么跨域、什么是预检请求(OPTIONS),我们不妨抛开抽象术语,用一个“魔法屋的故事”来解释。
一、浏览器:一间拥有魔法之门的屋子
可以这样想象:
浏览器就像是一座“魔法屋”,屋子里住着 JavaScript,它想打开门出去访问别的世界(服务器)获取资源。
这扇门很特别,它不是一扇通往固定地方的门,而是魔法之门——门后通向哪里,由 JavaScript 发出的请求(URL、端口、协议)来决定。
比如:
- JavaScript 请求
https://api.example.com
,门后就通往 api.example.com - 请求
http://localhost:8080
,门后就通往本地开发服务
但别忘了:这扇门并不是任何时候都能打开的!
屋子(浏览器)有一套同源策略,默认只允许去访问“同一个世界”(同源)。
二、什么是同源策略?
三要素完全相同,才叫“同源”:
- 协议(http / https)
- 域名(example.com)
- 端口(80 / 443 / 其他)
只要有一项不同,就算是另一个世界,需要经过验证才可以访问。
三、敲门之前要问一句:“我能进去吗?” —— 预检请求
当你发出一个“跨域”请求时,屋子里的 JavaScript 先不能直接开门,而是通过浏览器敲门:
“你好,我是从
http://localhost:3000
来的,我想用PUT
方法带一个Authorization
头去访问你,能让我进来吗?”
这就是所谓的 预检请求(Preflight Request),是由浏览器自动发出的 OPTIONS
请求。
四、什么情况下会触发预检请求?
只要你满足以下条件之一,浏览器就会“敲门确认”:
- 使用了
PUT
,DELETE
,PATCH
等非“简单方法” - 设置了自定义请求头(如
Authorization
,X-Token
) - 设置了非简单的
Content-Type
(如application/json
)
这些行为被视为“有风险”,所以浏览器会先问服务器:“你允许这样的请求吗?”
对于下面这部分感兴趣的可以参考这篇文章:哪些行为是有风险的?为什么?
五、服务器放不放人,看通行证(响应头)
如果服务器认可了请求,会给浏览器一个“通行证”:
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Authorization
Access-Control-Max-Age: 3600
这表示:
- 你来自
http://localhost:3000
,被允许访问 - 可以使用
GET/POST/PUT
方法 - 可以携带
Authorization
头 - 这张通行证在未来一小时内都有效
六、是不是只有写操作才跨域?
不是的!
即便是读取图片、视频等内容,只要是跨域来源,也会受到同源策略的限制。你虽然能加载它,但可能无法读取内容或处理响应体。
比如:
fetch('https://img.baidu.com/a.jpg')
// 若没有 Access-Control-Allow-Origin,将无法读取数据内容
七、魔法屋、魔法门与通行证:类比总结
概念 | 类比描述 |
---|---|
浏览器 | 魔法屋 |
JavaScript | 住在魔法屋里的法师 |
请求地址 | 魔法门后面通向的世界 |
同源策略 | 魔法屋的通行规则 |
跨域请求 | 尝试打开通往外面世界的魔法门 |
OPTIONS 请求 | 敲门:“我可以访问你吗?” |
CORS 响应头 | 通行证 / 放行许可 |
Access-Control-… | 具体说明:谁可以访问、能干什么等 |
八、开发实践中的建议
- ✅ 后端设置 CORS 头:Spring Boot、Node.js 等框架都内置支持
- ✅ 阿里云 / 腾讯云 OSS:在控制台设置跨域规则(允许 Origin、Method、Header)
- ✅ 缓存预检请求:设置
Access-Control-Max-Age
来减少重复请求 - ✅ 避免复杂请求触发预检(除非必要)
九、结语
如果你把“跨域”看作是一个前后端之间“门的游戏”,那么你就理解了浏览器为安全所设下的层层机制。
下次你看到 OPTIONS 请求,就不再觉得奇怪:这是浏览器为了你,在提前去敲门问“我能不能过去”。