一、为什么要跨域?
1. 什么是跨域?
跨域是指在网络中,不同域名下的网页或资源之间进行数据交换或通信时所面临的限制和问题。同源策略是浏览器的一种安全机制,它限制了一个域名下的网页脚本对另一个域名下的资源进行访问。当一个网页的源代码来自一个域名,而它所请求的资源来自另一个域名时,就会发生跨域问题。
2. 什么是同源策略?
同源策略是浏览器安全策略的一部分,它是一种基本的网络安全机制,用于限制一个网页从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。同源策略要求网页的源(协议、域名、端口)必须完全相同,才允许在浏览器中进行交互。
具体来说,同源策略规定了以下内容:
- 网页中的JavaScript只能访问与其所在页面具有相同源的资源。
- 网页中的XMLHttpRequest请求只能向同源的地址发起,不允许跨域请求。
- 网页中的Cookie、LocalStorage和IndexDB等存储的数据也只能访问同源的资源。
同源策略的存在可以有效防止恶意网站对用户数据的窃取和篡改,从而提高了网络安全性。但同时也会对网页开发者造成一定的限制,因为它限制了不同源的资源之间的交互和访问。为了解决跨域问题,可以使用一些方法来绕过同源策略的限制,例如JSONP、CORS、代理、iframe、跨文档消息等。
二、跨域的解决方案
1. JSONP(JSON with Padding)
JSONP是一种利用<script>标签的src属性不受同源策略限制的特性来实现跨域数据传输的方法。通过在请求URL中添加一个回调函数名,服务端返回的数据会被包裹在这个回调函数中,然后在客户端执行该回调函数来获取数据。
<script>
// 回调执行函数
const jsonpCallback = (data) => {
console.log(data);
}
const script = document.createElement('script');
// 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数
script.src = 'http://example.com/api/data?callback=jsonpCallback';
document.body.appendChild(script);
</script>
2. CORS(跨域资源共享)
CORS是一种由W3C标准化的跨域解决方案,通过在服务端设置响应头中的Access-Control-Allow-Origin字段,允许指定的域名访问资源,从而实现跨域数据交换。
// Node.js示例
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Origin', 'http://example.com');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
});
3. 代理
通过在自己的服务器上设置代理,来转发跨域请求。客户端将请求发送到自己的服务器上,再由服务器转发到目标服务器,然后将返回结果再返回给客户端。
// Node.js示例
app.get('/proxy', function(req, res) {
request('http://example.com/api/data', function(error, response, body) {
if (!error && response.statusCode == 200) {
res.send(body);
}
});
});
4. iframe
利用iframe的src属性不受同源策略限制的特性,可以通过在页面中嵌入一个隐藏的iframe来实现跨域通信。
<iframe src="http://example.com/endpoint" style="display:none;"></iframe>
5. 跨文档消息(Cross-document messaging)
使用window.postMessage()方法在不同域的窗口之间进行安全的跨域通信。
// 发送消息
otherWindow.postMessage('Hello', 'http://example.com');
// 接收消息
window.addEventListener('message', function(event) {
if (event.origin === 'http://example.com') {
console.log('Received message: ' + event.data);
}
});