1. 什么是跨域?

跨域(Cross-Origin)是指瀏覽器出于安全考慮,限制不同源(協(xié)議、域名、端口)之間的資源交互。
同源策略(Same-Origin Policy) 要求以下三者必須一致:
2. 跨域的表現(xiàn)形式
當(dāng)以下場(chǎng)景發(fā)生在不同源時(shí),瀏覽器會(huì)攔截請(qǐng)求:
3. 常見(jiàn)跨域解決方案
3.1 CORS(跨域資源共享)
原理:服務(wù)端通過(guò)響應(yīng)頭聲明允許的跨域請(qǐng)求來(lái)源。
實(shí)現(xiàn)步驟:
1.簡(jiǎn)單請(qǐng)求(GET/POST/HEAD,Content-Type 為 text/plain
、multipart/form-data
、application/x-www-form-urlencoded
):
服務(wù)端返回 Access-Control-Allow-Origin: *
或具體域名。
2.預(yù)檢請(qǐng)求(復(fù)雜請(qǐng)求如 PUT/DELETE 或自定義頭):
瀏覽器先發(fā)送 OPTIONS
請(qǐng)求,服務(wù)端需響應(yīng):
Access-Control-Allow-Origin: https://your-domain.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization
示例代碼(Node.js Express):
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "https://your-client.com");
res.header("Access-Control-Allow-Headers", "Content-Type, Authorization");
res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
if (req.method === "OPTIONS") {
return res.sendStatus(200); // 快速返回預(yù)檢請(qǐng)求響應(yīng)
}
next();
});
3.2 JSONP(JSON with Padding)
原理:利用 <script>
標(biāo)簽無(wú)跨域限制的特性,通過(guò)回調(diào)函數(shù)獲取數(shù)據(jù)。
缺點(diǎn):僅支持 GET 請(qǐng)求,存在安全風(fēng)險(xiǎn)(如 XSS)。
示例代碼:
// 前端
function handleResponse(data) {
console.log("Received:", data);
}
const script = document.createElement('script');
script.src = 'https://api.example.com/data?callback=handleResponse';
document.body.appendChild(script);
// 服務(wù)端返回
handleResponse({ "status": "success", "data": [...] });
3.3 代理服務(wù)器
原理:通過(guò)同源的后端服務(wù)轉(zhuǎn)發(fā)請(qǐng)求,繞過(guò)瀏覽器限制。
實(shí)現(xiàn)方式:
location /api/ {
proxy_pass https://api.example.com/;
proxy_set_header Host $host;
}
開(kāi)發(fā)環(huán)境代理(如 webpack-dev-server)
// vue.config.js / webpack.config.js
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'https://api.example.com',
changeOrigin: true,
}
}
}
};
3.4 WebSocket
原理:WebSocket 協(xié)議不受同源策略限制。
?示例代碼:
const socket = new WebSocket('wss://api.example.com/socket');
socket.onmessage = (event) => {
console.log('Message:', event.data);
};
3.5 其他方案
document.domain = "example.com";
postMessage API
用于窗口間通信(如 <iframe>
與父頁(yè)面):
// 發(fā)送方
window.parent.postMessage('Hello', 'https://parent-domain.com');
// 接收方
window.addEventListener('message', (event) => {
if (event.origin !== 'https://child-domain.com') return;
console.log('Received:', event.data);
});
4. 調(diào)試與注意事項(xiàng)
// 前端
fetch(url, { credentials: 'include' });
// 服務(wù)端
res.header("Access-Control-Allow-Credentials", "true");
res.header("Access-Control-Allow-Origin", "https://your-client.com"); // 不能為通配符 *
?
5. 總結(jié)
推薦方案:優(yōu)先使用 CORS 或代理服務(wù)器。
兼容性場(chǎng)景:JSONP 適用于老舊系統(tǒng)。
實(shí)時(shí)通信:WebSocket 是理想選擇。
通過(guò)理解跨域機(jī)制及解決方案,開(kāi)發(fā)者可靈活應(yīng)對(duì)不同場(chǎng)景的跨域需求。
該文章在 2025/2/20 16:59:28 編輯過(guò)