在 Web 开发中,浏览器的同源策略(Same-Origin Policy)限制了不同源(协议、域名、端口)之间的资源访问。因此,跨域请求会受到同源策略的限制,但在某些情况下,我们确实需要进行跨域请求。以下是几种常见的跨域解决方案:
- JSONP(JSON with Padding):JSONP 是通过动态创建
<script>
元素来实现的,利用<script>
元素的跨域特性来获取远程数据。但 JSONP 只支持 GET 请求,且只能接收 JSON 格式的数据,相对有一定的局限性。
function jsonpRequest(url, callback) {
const script = document.createElement('script');
script.src = url;
// 通过回调函数处理返回的数据
window.callbackFunction = function(data) {
callback(data);
document.body.removeChild(script);
};
document.body.appendChild(script);
}
// 调用示例
jsonpRequest('https://www.baidu.com/api?callback=callbackFunction', function(data) {
console.log(data);
});
- CORS(跨域资源共享):CORS 是一种在服务器端设置的机制,通过在响应头中添加特定的字段来告知浏览器该资源允许被哪些源进行访问。服务器可以设置响应头的
Access-Control-Allow-Origin
字段来指定允许的源,也可以设置其他字段来控制更细粒度的请求。
const xhr = new XMLHttpRequest();
xhr.open('GET', 'http://example.com/api', true);
// 设置请求头,允许来源的域名访问
xhr.setRequestHeader('Access-Control-Allow-Origin', 'https://www.baidu.com');
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 400) {
const data = JSON.parse(xhr.responseText);
console.log(data);
}
};
xhr.send();
- 代理服务器:可以通过在同域名下的服务器上设置一个代理,让该代理服务器去请求目标服务器的资源,并将结果返回给前端。前端通过访问同域名下的代理服务器来绕过跨域限制。
const express = require('express');
const httpProxy = require('http-proxy');
const app = express();
const apiProxy = httpProxy.createProxyServer();
app.all('/api', function(req, res) {
apiProxy.web(req, res, { target: 'https://www.baidu.com' });
});
app.listen(3000);
- postMessage API:postMessage 是一种 HTML5 提供的跨文档通信方式,它允许在不同窗口(包括不同域名、协议和端口)之间进行安全的消息传递。可以利用 postMessage 实现跨域数据传输和通信。
// 父窗口(A域名)
window.addEventListener('message', function(event) {
if (event.origin !== 'https://www.baidu.com') {
return;
}
console.log(event.data); // 接收到的数据
});
// 子窗口(B域名)
window.parent.postMessage('Hello from B domain!', 'https://www.baidu.com');
- WebSocket:WebSocket 是一种全双工的通信协议,可以通过 JavaScript 建立与服务器的长连接。WebSocket 不受同源策略的限制,可以在不同域之间进行实时通信。
// 客户端
const socket = new WebSocket('ws://example.com/socket');
socket.onopen = function() {
console.log('WebSocket 连接已建立');
socket.send('Hello server!');
};
socket.onmessage = function(event) {
console.log('收到服务器端消息:', event.data);
};
// 服务器端(Node.js + ws 模块)
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function(ws) {
console.log('客户端已连接');
ws.on('message', function(message) {
console.log('收到客户端消息:', message);
ws.send('Hello client!');
});
});
需要注意的是,不同的解决方案适用于不同的场景,选择最佳的解决方案应考虑到安全性、兼容性和便利性等因素。