前端跨域

1.什么是跨域

跨域就是请求同源策略限制的请求

什么是同源策略

同源策略是一种约定,域名、协议、端口号相同即为同源,帮助我们在浏览器进行隔离。

目的:为了保护用户信息的安全,防止恶意窃取数据

哪些是受同源策略限制的对象

1.cookie、localStorage 和 indexDB 无法读取等
2.dom 无法获得
3.ajax 不能发送

不受同源策略限制的对象

1.表单提交
2.img、iframe、script(jsonp)、link

2.前端跨域的几种方式

2.1 Jsonp 跨域

jsonp 的原理就是利用 script 标签没有同源策略限制,通过 script 标签 src 属性,发送带有 callback 参数的 GET 请求,服务端接口返回数据拼凑到 callback 函数中,浏览器收到响应就会执行 callback 函数,接下来看我之前写过的> 例子,会一目了然,简单列举一下

//客户端
    var script = document.createElement('script');
    script.type = 'text/javascript';

    // 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数
    script.src = 'http://www.duanxl.com:8080/getuser?callback=handleCallback';
    document.head.appendChild(script);
    // 回调执行函数
    function handleCallback(res) {
        alert(JSON.stringify(res));
    }
//服务端
ctx.res.write(`<script>initResoure("${content}")</script>`);

2.2 跨资源共享 CORS

CORS 是 W3c 的一个标准,允许浏览器向跨源服务器请求数据
我们可以通过配置响应头来达到跨域许可,用于说明接收哪些可允许的域
1.Access-Control-Allow-Origin 必选,它的值要么是请求时 Origin 字段的值,要么是一个*,表示接受任意域名的请求。
2.Access-Control-Allow-Credentials 可选,是一个 Boolean 值,表示是否发送 cookie
3.Access-Control-Expose-Headers 可选,是否可以拿到其他字段

2.3 nginx 代理跨域

与上面的 CORS 原理一样,通过配置文件设置响应头等字段

2.4 node 中间件代理跨域

我们知道在使用 BFF 架构模式时,node 本身帮我们解决了跨域问题,具体就不说了

2.5 document.domain

比如我们有两个网页一级域名相同,二级域名不同,我们可以通过设置 document.domian 来解决跨域

document.domain共享cookie
test.xxx.com a.html
==================
<script>
document.cookie="aaa";
document.domain="test.com";
</script>

test2.xxx.com b.html
===================
<script>
var data=document.cookie;
</script>

当然,我们也可以配置 iframe 等方式,再通过 location.hash 传值,达到域之间的数据共享

2.6 window.name+iframe

我们知道,当使用了 iframe 时,window.name 将共享当前数据,window.name 一般是指 window 的名称,window.name 可以容纳很大的值(最大 2M),我们完全可以将需要共享的数据放在 window.name 上,这样也是解决跨域的一种方式

2.7 postMessage

postMessage 是 html5 新的 api,接收两个参数 postMessage(data,orign)
第一个参数只能是字符串,我们可以使用 JSON.stringify 序列化数据

//a.html
window.postMessage('test data','http://www.domain.com')
//b.html
window.addEventListener('message', function(e) {
    alert('data from domain2 ---> ' + e.data);
}, false);

2.8 webSocket 跨域

WebSocket protocol 是 HTML5 一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是 server push 技术的一种很好的实现。

//客户端
const url='ws://xxx.xxx:2222';
const socket=new WebSocket(url);
socket.onopen=()=>{
    //成功建立时触发
}
socket.onmessage=(data)=>{
    //收到消息时触发
}
socket.onclose=()=>{
    //断开链接时触发
}
socket.onerror=(e)=>{
    //异常
}
//服务端我们可以使用socket-io,这里我就不写了,明白用法即可

2.9 BroastcastChannel 和 MessageChannel 实现跨域

MessageChannel 又称为点对点通信,就是两个对端口,一个发送,一个接收

var channel = new MessageChannel();
var para = document.querySelector('p');

var ifr = document.querySelector('iframe');
var otherWindow = ifr.contentWindow;

ifr.addEventListener("load", iframeLoaded, false);

function iframeLoaded() {
  otherWindow.postMessage('Hello from the main page!', '*', [channel.port2]);
}

channel.port1.onmessage = handleMessage;
function handleMessage(e) {
  para.innerHTML = e.data;
}

BroastcastChannel 又称为广播消息

const bc = new BroadcastChannel('channel1')
const bc2 = new BroadcastChannel('channel1')

bc2.onmessage = (eve) => {
    console.log('bc:', eve.data);
}

setTimeout(() => {
    bc.postMessage({message: 'hello'})
}, 1000);

其实 BroastcastChannel、MessageChannel、PostMessage 这三种方式都可以实现深拷贝,因为我们可以利用通信,将对象直接发送,这也算是一种特例
当然,还有很多解决跨域的方法,比如 jQuery、axios 等提供的 API,先简单介绍到这里,如果有理解不对的地方,欢迎联系我微信:d15540940134

0
`);\n' + '```\n' + '\n' + '### 2.2 跨资源共享 CORS\n' + '\n' + '> CORS 是 W3c 的一个标准,允许浏览器向跨源服务器请求数据 \n' + '> 我们可以通过配置响应头来达到跨域许可,用于说明接收哪些可允许的域 \n' + '> 1.Access-Control-Allow-Origin 必选,它的值要么是请求时 Origin 字段的值,要么是一个\\*,表示接受任意域名的请求。 \n' + '> 2.Access-Control-Allow-Credentials 可选,是一个 Boolean 值,表示是否发送 cookie \n' + '> 3.Access-Control-Expose-Headers 可选,是否可以拿到其他字段\n' + '\n' + '### 2.3 nginx 代理跨域\n' + '\n' + '> 与上面的 CORS 原理一样,通过配置文件设置响应头等字段\n' + '\n' + '### 2.4 node 中间件代理跨域\n' + '\n' + '> 我们知道在使用 BFF 架构模式时,node 本身帮我们解决了跨域问题,具体就不说了\n' + '\n' + '### 2.5 document.domain\n' + '\n' + '> 比如我们有两个网页一级域名相同,二级域名不同,我们可以通过设置 document.domian 来解决跨域\n' + '\n' + '```\n' + 'document.domain共享cookie\n' + 'test.xxx.com a.html\n' + '==================\n' + '\n' + '\n' + 'test2.xxx.com b.html\n' + '===================\n' + '\n' + '```\n' + '\n' + '> 当然,我们也可以配置 iframe 等方式,再通过 location.hash 传值,达到域之间的数据共享\n' + '\n' + '### 2.6 window.name+iframe\n' + '\n' + '> 我们知道,当使用了 iframe 时,window.name 将共享当前数据,window.name 一般是指 window 的名称,window.name 可以容纳很大的值(最大 2M),我们完全可以将需要共享的数据放在 window.name 上,这样也是解决跨域的一种方式\n' + '\n' + '### 2.7 postMessage\n' + '\n' + '> postMessage 是 html5 新的 api,接收两个参数 postMessage(data,orign)\n' + '> 第一个参数只能是字符串,我们可以使用 JSON.stringify 序列化数据\n' + '\n' + '```\n' + '//a.html\n' + "window.postMessage('test data','http://www.domain.com')\n" + '//b.html\n' + "window.addEventListener('message', function(e) {\n" + " alert('data from domain2 ---> ' + e.data);\n" + '}, false);\n' + '```\n' + '\n' + '### 2.8 webSocket 跨域\n' + '\n' + '> WebSocket protocol 是 HTML5 一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是 server push 技术的一种很好的实现。\n' + '\n' + '```\n' + '//客户端\n' + "const url='ws://xxx.xxx:2222';\n" + 'const socket=new WebSocket(url);\n' + 'socket.onopen=()=>{\n' + ' //成功建立时触发\n' + '}\n' + 'socket.onmessage=(data)=>{\n' + ' //收到消息时触发\n' + '}\n' + 'socket.onclose=()=>{\n' + ' //断开链接时触发\n' + '}\n' + 'socket.onerror=(e)=>{\n' + ' //异常\n' + '}\n' + '//服务端我们可以使用socket-io,这里我就不写了,明白用法即可\n' + '```\n' + '\n' + '### 2.9 BroastcastChannel 和 MessageChannel 实现跨域\n' + '\n' + '> MessageChannel 又称为点对点通信,就是两个对端口,一个发送,一个接收\n' + '\n' + '```\n' + 'var channel = new MessageChannel();\n' + "var para = document.querySelector('p');\n" + '\n' + "var ifr = document.querySelector('iframe');\n" + 'var otherWindow = ifr.contentWindow;\n' + '\n' + 'ifr.addEventListener("load", iframeLoaded, false);\n' + '\n' + 'function iframeLoaded() {\n' + " otherWindow.postMessage('Hello from the main page!', '*', [channel.port2]);\n" + '}\n' + '\n' + 'channel.port1.onmessage = handleMessage;\n' + 'function handleMessage(e) {\n' + ' para.innerHTML = e.data;\n' + '}\n' + '```\n' + '\n' + 'BroastcastChannel 又称为广播消息\n' + '\n' + '```\n' + "const bc = new BroadcastChannel('channel1')\n" + "const bc2 = new BroadcastChannel('channel1')\n" + '\n' + 'bc2.onmessage = (eve) => {\n' + " console.log('bc:', eve.data);\n" + '}\n' + '\n' + 'setTimeout(() => {\n' + " bc.postMessage({message: 'hello'})\n" + '}, 1000);\n' + '\n' + '```\n' + '\n' + '> 其实 BroastcastChannel、MessageChannel、PostMessage 这三种方式都可以实现深拷贝,因为我们可以利用通信,将对象直接发送,这也算是一种特例 \n' + '> 当然,还有很多解决跨域的方法,比如 jQuery、axios 等提供的 API,先简单介绍到这里,如果有理解不对的地方,欢迎联系我微信:d15540940134\n', title: 'xl学习之路 | 段鑫磊 | 段鑫磊的博客 | 前端技术', type: 'detail' }