什么是跨域?有哪些解决跨域的方案?
同源策略
浏览器安全策略:协议、域名、端口三者完全相同才算同源。不同源的请求默认被浏览器拦截。
跨域解决方案
1. CORS(最常用)
服务端设置响应头允许跨域:
# 简单请求
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Credentials: true
# 预检请求响应
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400简单请求条件(同时满足):
- 方法为 GET/HEAD/POST
- Content-Type 为 text/plain、multipart/form-data、application/x-www-form-urlencoded
- 不含自定义头部
预检请求(OPTIONS):
- 非简单请求先发 OPTIONS 请求询问是否允许
- 浏览器根据响应决定是否发送真实请求
// Node.js Express 示例
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', 'https://example.com')
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE')
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization')
if (req.method === 'OPTIONS') {
return res.sendStatus(200)
}
next()
})2. 代理服务器
浏览器 → 同源代理服务器 → 目标服务器// Vite 配置
export default {
server: {
proxy: {
'/api': {
target: 'http://backend.com',
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, '')
}
}
}
}3. JSONP(已过时)
利用 <script> 标签不受同源策略限制:
function handleData(data) { console.log(data) }
const script = document.createElement('script')
script.src = 'https://api.example.com/data?callback=handleData'
document.body.appendChild(script)
// 服务器返回: handleData({ name: 'Tom' })- ✅ 兼容老浏览器
- ❌ 只支持 GET、不安全、已过时
4. postMessage(跨窗口通信)
// 父窗口 → iframe
iframe.contentWindow.postMessage('hello', 'https://child.com')
// iframe 接收
window.addEventListener('message', (e) => {
if (e.origin === 'https://parent.com') {
console.log(e.data)
}
})5. WebSocket
WebSocket 不受同源策略限制:
const ws = new WebSocket('ws://example.com/socket')
ws.onmessage = (e) => console.log(e.data)带凭证的跨域
fetch('https://api.example.com/data', {
credentials: 'include' // 携带 Cookie
})
// 服务端必须设置
// Access-Control-Allow-Origin: 具体域名(不能用 *)
// Access-Control-Allow-Credentials: true