小白友好版,跨域不再迷路
1️⃣ 什么是跨域?
跨域,简单理解就是:
"浏览器:哎呀,这请求要跑到别人家去拿数据,我敢不敢让它去呢?"
严格说法:当浏览器从一个源(Origin)请求另一个源(Origin)的资源时,如果两者不一样,就触发同源策略(Same-Origin Policy),这就是跨域。
源(Origin)组成:
源 = 协议(Protocol) + 域名(Host) + 端口(Port)
三者任意一项不同,就算跨域。
为什么有同源策略?
- 防止 CSRF(跨站请求伪造)
- 防止 XSS(跨站脚本攻击)
- 防止隐私泄露(Cookie、账户信息)
举个例子:
bash
http://example.com:80/page1.html → http://api.example.com:80/data
域名不同 → 跨域
2️⃣ CORS(跨域资源共享)
CORS 就像浏览器和服务器的"通行证",谁允许你进,谁说了算。
浏览器:我想拿数据!
服务器:你是安全的,我允许你。
浏览器:好,我拿走数据!
2.1 两种 CORS 请求
🔹 简单请求(Simple Request)
条件(全部满足):
- 方法:
GET
/POST
/HEAD
- 请求头:只能是浏览器安全集合
- 请求体:安全格式(纯文本/表单)
javascript
// 简单请求示例
fetch('https://api.example.com/data', {
method: 'GET',
})
.then(res => res.json())
.then(data => console.log(data));
服务器只需允许跨域即可:
makefile
Access-Control-Allow-Origin: *
🔹 预检请求(Preflight Request)
触发条件:
- 方法不是 GET/POST/HEAD
- 自定义请求头(如
X-Token
) - Content-Type 非简单类型
流程示意:
浏览器:我想PUT数据,可以吗?(OPTIONS预检)
服务器:可以,你的来源、方法、头都允许
浏览器:好,发真正请求
代码示例:
javascript
fetch('https://api.example.com/data', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-Token': '123456'
},
body: JSON.stringify({ name: '跨域小白' })
})
.then(res => res.json())
.then(data => console.log(data));
面试小技巧:能区分"简单请求 vs 预检请求",CORS 面试题轻松过。
3️⃣ JSONP
JSONP 是老派跨域方式,利用 <script>
标签天生跨域的特性。
xml
<script>
function handleData(data) {
console.log('拿到跨域数据啦!', data);
}
</script>
<script src="https://api.example.com/data?callback=handleData"></script>
优点 :兼容老浏览器、实现简单
缺点:只能 GET、XSS 风险、错误处理麻烦
现代项目基本不用 JSONP,直接 CORS + Fetch 就好。
4️⃣ postMessage
当你和不同源的 iframe/窗口要聊聊时,postMessage
就像安全的对讲机。
xml
<!-- 父页面 -->
<iframe id="child" src="https://other.com"></iframe>
<script>
const iframe = document.getElementById('child');
iframe.contentWindow.postMessage({ msg: 'Hi小伙伴' }, 'https://other.com');
window.addEventListener('message', (event) => {
if(event.origin !== 'https://other.com') return; // 安全检查
console.log('收到子页面消息:', event.data);
});
</script>
记住:安全第一,一定要检查
event.origin
!
5️⃣ WebSocket
WebSocket 就是"前端的即时聊天神器",浏览器和服务器可以随时互发消息。
ini
const ws = new WebSocket('wss://example.com/socket');
ws.onopen = () => ws.send('hello server!');
ws.onmessage = (msg) => console.log('收到服务器消息:', msg.data);
ws.onclose = () => console.log('连接关闭');
特点:
- 全双工
- 单连接
- 跨域天然支持
6️⃣ 跨域常见应用场景
场景 | 示例 | 解决方案 | 代码示例 |
---|---|---|---|
前端调用后端 API | 开发 localhost → 远端 API | CORS / 反向代理 | fetch('https://api.example.com') |
第三方接口 | 高德地图、支付 | CORS / JSONP | fetch('https://maps.com/api') |
跨域 iframe 通信 | 支付 iframe | postMessage | iframe.contentWindow.postMessage(...) |
多窗口/标签页 | 登录状态同步 | postMessage + window.open | window.opener.postMessage(...) |
Web Worker 跨域 | Worker 加载脚本 | postMessage + CORS | worker.postMessage(...) |
静态资源跨域 | CDN JS/CSS/图片 | 允许跨域 | <script src="https://cdn.com/lib.js"></script> |
7️⃣ 面试问答专栏:跨域篇
1️⃣ 面试官问:什么是跨域?
回答示例:
"跨域就是浏览器发现你要去访问别人家的资源,它会先问一句:我敢不敢让它去?
严格来说,就是源(协议 + 域名 + 端口)不同,就触发同源策略。"
2️⃣ 面试官问:什么是 CORS?
回答示例:
"CORS 就是浏览器和服务器的通行证,服务器在响应头声明允许的源、方法、头,浏览器通过才交数据给前端。
简单请求直接发,复杂请求会先发 OPTIONS 预检。"
代码示例:
ini
fetch('https://api.example.com/data')
.then(res => res.json())
.then(data => console.log(data));
3️⃣ 面试官问:JSONP 和 CORS 有什么区别?
回答示例:
"JSONP 是老派方案,靠
<script>
标签跨域,只能 GET,有 XSS 风险。CORS 是现代方案,更安全灵活,支持 POST/PUT/DELETE。"
4️⃣ 面试官问:postMessage 是什么?
回答示例:
"父页面和 iframe 或者窗口与 Worker 需要互相通信时,用 postMessage 传消息。安全重点是检查 event.origin。"
代码示例:
css
iframe.contentWindow.postMessage({ msg: 'hello' }, 'https://other.com');
5️⃣ 面试官问:WebSocket 跨域吗?
回答示例:
"WebSocket 建立的是 TCP 长连接,一旦连接建立就天然跨域,可以双向通信。"
8️⃣ 总结
跨域知识点其实就像"安检关卡",理解它,你就能安全访问资源,而且面试题轻松拿分。
技术 | 适用场景 | 优点 | 注意点 |
---|---|---|---|
CORS | 前后端接口跨域 | 简单灵活 | 后端需支持 |
JSONP | 老 GET 请求 | 兼容老浏览器 | 只能 GET、有 XSS 风险 |
postMessage | iframe/窗口/Worker 通信 | 安全灵活 | 检查 origin |
WebSocket | 实时通信 | 高效全双工 | 服务端支持 |
✅ 小结:
- CORS → 现代前端首选
- JSONP → 老项目遗留
- postMessage → 窗口/iframe/Worker 通信
- WebSocket → 实时双向通信
跨域学会了,你就是前端安全小能手!