跨域江湖:六大绝技🗡️
你是否曾在开发时遇到过“跨域”这个让人头秃的家伙?今天我们就来聊聊前端跨域的那些事儿,带你从原理到实战,轻松掌握各种跨域姿势!
一、同源策略:前端的“护城河” 🏰
同源策略(Same-Origin Policy)是浏览器的一道安全防线。只有协议、域名、端口都相同的两个源,才能愉快地访问彼此的数据。否则,浏览器就会像门神一样把你拦在门外。
同源策略主要保护的是响应数据,而不是请求数据。所以我们可以通过一些骚操作来“曲线救国”。
二、跨域的六大绝技 🌈
1. JSONP:老牌跨域选手,GET请求专属
原理:利用<script>
标签的src
属性不受同源策略限制,通过动态创建<script>
标签向跨域服务器发送请求。前端把回调函数名作为参数传给后端,后端把数据包装成该回调函数的调用形式返回,前端提前定义好同名函数来接收数据。
前端代码:
<script>
function jsonp(url, cb) {
return new Promise((resolve,
reject) => {
const script = document.
createElement('script')
script.src = `${url}?cb=$
{cb}`
window[cb] = function
(data) {
resolve(data)
}
document.body.appendChild
(script)
})
}
jsonp('http://localhost:3000',
'callback').then(res => {
console.log(res);
})
</script>
服务端代码:
const http = require('http')
const server = http.createServer
((req, res) => {
const query = new URL(req.url,
`http://${req.headers.host}`).
searchParams
if (query.get('cb')) {
const cb = query.get('cb')
const data = 'hello world'
const result = `${cb}("$
{data}")`
res.end(result)
}
})
server.listen(3000, () => {
console.log('server is
running')
})
缺陷:
- 只支持GET请求
- 必须后端配合
- 有安全隐患(比如XSS)
2. CORS:现代浏览器的官方跨域方案
原理:后端在响应头中配置允许的源、方法、头信息,告诉浏览器“这家伙我认识,放他进来”。
代码片段:
const http = require('http')
const server = http.createServer((req, res) => {
res.writeHead(200, {
'Access-Control-Allow-Origin': 'http://127.0.0.1:5500',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization'
})
res.end('hello cors')
})
server.listen(3000, () => {
console.log('server is running')
})
优点:支持各种HTTP方法,安全性高,灵活配置。
3. 反向代理:nginx/node双剑合璧
原理:利用nginx或node的代理能力,把前端的请求转发到后端服务器,再把响应返回给前端。前端眼里只有代理服务器,后端的真实地址被“隐藏”了。
前端代码:
<script>
const xhr = new XMLHttpRequest()
xhr.open('GET', 'http://
localhost:3000')
xhr.send()
xhr.onreadystatechange = function
() {
if (xhr.readyState === 4 &&
xhr.status === 200) {
console.log(xhr.
responseText);
}
}
</script>
服务端代码:
const http =require('http')
const server = http.createServer
((req, res) => {
res.writeHead(200, {
'Access-Control-Allow-Origi
n': 'http://127.0.0.
1:5500',
'Access-Control-Allow-Metho
ds': 'GET, POST, PUT,
DELETE, OPTIONS',
'Access-Control-Allow-Heade
rs': 'Content-Type,
Authorization'
})
http.request({
host: '192.168.1.75',
port: '3000',
method: 'GET',
path: '/',
headers: {}
}, (proxyRes) => {
proxyRes.on('data', (data)
=> {
res.end(data.toString
())
})
}).end()
})
server.listen(3000, () => {
console.log('server is running
3000')
})
优点:支持各种请求,安全灵活,适合大型项目。
4. WebSocket:实时通信的跨域利器
原理:WebSocket协议可以在浏览器和服务器之间建立持久连接,实现全双工通信,不受同源策略限制。
前端代码:
<script>
function myWebSocket(url, params) {
return new Promise((resolve,
reject) => {
const socket = new
WebSocket(url)
socket.onopen = () => {
socket.send(JSON.
stringify(params))
}
socket.onmessage = (res)
=> {
console.log(`从服务端接
收到的数据: ${res.data}
`);
}
})
}
myWebSocket('ws://localhost:3000',
{age: 18})
</script>
服务端代码:
const webSocket = require('ws')
const ws = new webSocket.Server({
port: 3000 })
let count = 0
ws.on('connection', (socket) => {
socket.on('message', (data) =>
{
socket.send('欢迎访问服务端')
setInterval(() => {
count++
socket.send(count)
}, 5000)
})
})
优点:实时性强,适合聊天室、游戏等场景。
5. postMessage:iframe页面间的“传话筒”
原理:当一个页面通过iframe嵌套了另一个页面,两个页面要通信时,利用postMessage
方法安全地传递消息。
一级页面代码:
<script>
let obj = { name: 'xxx', age: 19 }
let frame = document.getElementById
('frame')
frame.onload = function () {
this.contentWindow.postMessage
(JSON.stringify(obj), 'http://
127.0.0.1:8080')
}
window.onmessage = function (e) {
console.log(`从二级页面接收的数据
: ${e.data}`);
}
</script>
二级页面代码:
<script>
window.onmessage = function(e) {
console.log(`从一级页面接收的数据
: ${e.data}`);
document.getElementById
('span').innerHTML = e.data
const {age} = JSON.parse(e.
data)
setTimeout(() => {
e.source.postMessage(`我是
二级页面, 我收到了一级页面的消
息, 我收到的消息中的年龄是: $
{age}`, e.origin)
}, 2000)
}
</script>
优点:安全、灵活,支持多窗口、iframe等多种场景。
6. document.domain:二级域名间的“亲兄弟”通信
原理:当两个页面的主域名不同,但二级域名相同,可以通过设置document.domain
为相同的主域名,实现跨域通信。
代码片段:
// 一级页面和二级页面都加上
document.domain = 'test.com'
注意:只适用于主域名相同的情况,比如:
三、跨域那些坑,你踩过几个?🕳️
- JSONP只能GET,POST就歇菜了
- CORS要后端配合,前端单干不行
- 代理要配置好路径,别把自己绕晕了
- WebSocket要注意协议和端口
- postMessage要校验origin,别让坏人钻空子
- document.domain只适合二级域名
四、跨域的未来:安全与便利并存 🚀
随着前端技术的发展,跨域方案越来越丰富,但安全永远是第一位。无论用哪种方法,都要记得防范XSS、CSRF等安全问题。
五、结语:跨域不再是“拦路虎” 🐯
前端跨域其实没那么可怕,只要掌握了这些绝技,遇到问题就能游刃有余。希望这篇文章能帮你理清思路,少踩坑,多写代码,早日成为跨域老司机!