此篇文章是对跨域知识的补充,由于前面一篇已经介绍了 JSONP 这种跨域方式,这里就不再多赘述
前言
先总体来说说跨域的几种方式吧
JSONP
通过动态生成
script
标签的方式来进行不同源网页之间的数据传递,具体看 这篇博客CORS
全称 跨源资源共享(Cross-Origin Resource Sharing),是目前 主流的 跨域方案
postMessage
HTML5 的一个 api,使用它也可以进行跨域操作
CORS
这个 CORS 要怎么进行跨域呢?很简单,它的原理就是 设置 HTTP 请求头,一般来讲在前后端进行 Ajax 通信时使用,比如 xxx.com 想向 yyy.com 发送 Ajax 请求// xxx.com 前端 Ajax 代码
let xhr = new XMLHttpRequest();
xhr.open('GET', 'yyy.com', true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText);
}
};
xhr.send();
这个时候你去打开控制台,会看到一个 Access-Control-Allow-Origin
的错误,就是说你进行跨域请求了,但是 yyy.com 上的服务器没有给你跨域的控制权限,所以你需要 在 yyy.com 这个服务器上设置 Access-Control-Allow-Origin 这个 HTTP 头,使它允许来自 xxx.com 的请求// 假设你的后端是基于 node.js 写的
var server = http.createServer(function(request, response){
...
response.setHeader('Access-Control-Allow-Origin', 'yyy.com');
...
}
...
当然了,你也可以图方便,将 Access-Control-Allow-Origin
设置成 *
, 表示允许任意源的请求,若你不想这样,想要允许多个源的请求,你可以这样设置var server = http.createServer(function(request, response){
...
if (request.headers.origin === 'yyy.com'
|| request.headers.origin === 'zzz.com') {
response.setHeader('Access-Control-Allow-Origin', request.headers.origin);
}
...
}
...
可是对于简单请求(GET
, POST
, HEAD
)来说,只是需要设置这一个头就行了,假如需要非简单的请求呢(PUT
, DELETE
),这个时候浏览器一般会发送一个 预请求, 这个预请求的格式如下Request Method: OPTIONS
所以相应的服务端需要设置 Access-Control-Allow-Methods
这个头,浏览器才能用 非简单请求进行通信var server = http.createServer(function(request, response){
...
if (request.headers.origin === 'yyy.com'
|| request.headers.origin === 'zzz.com') {
response.setHeader('Access-Control-Allow-Origin', request.headers.origin);
response.setHeader('Access-Control-Allow-Methods', 'put,delete');
}
...
}
如果你还想要传送 Cookie ,你需要在浏览器端设置 withCredentials
, 然后在服务器端设置 Access-Control-Allow-Credentials
头// xxx.com 前端 Ajax 代码
...
xhr.withCredentials = true;
...
// yyy.com 后端代码
var server = http.createServer(function(request, response){
...
response.setHeader('Access-Control-Allow-Credentials', true);
...
}
postMessage
使用方法: postMessage('需要发送的消息', '对方域名')
<!-- xxx.com 前端代码 -->
<iframe id="iframe" src="yyy.com"></iframe>
<script>
let iframe = document.querySelector('#iframe');
iframe.setAttribute('style', 'display: none');
iframe.onload = function() {
iframe.contentWindow.postMessage('我是 xxx.com', 'yyy.com');
}
</script>
<!-- yyy.com 前端代码 -->
<script>
window.addEventListener('message', function(e) {
console.log(e.data, e.origin);
});
</script>
还有其他的方式?
hash + iframe
当然还有其他的方式了,比如有一种 hash + iframe
<!-- xxx.com 前端代码 -->
<iframe id="iframe" src="yyy.com"></iframe>
<script>
let iframe = document.querySelector('#iframe');
iframe.setAttribute('style', 'display: none');
iframe.src = iframe.src + '#' + JSON.stringify({data: 'hash'});
</script>
<!-- yyy.com 前端代码 -->
window.onhashchange = function() {
console.log(window.location.hash);
}
原理: 动态改变 iframe
src 属性的 hash 值,然后接受方通过监听 onhashchange
这个事件来接受到其传过来的数据
WebSockets
WebSockets
的基础用法如下const ws = new WebSocket('ws://xxx.com');
ws.onopen = function() {
// 连接成功建立
}
ws.onmessage = function(event) {
// 处理数据
}
ws.onerror = function() {
// 发生错误时触发,连接中断
}
ws.onclose = function() {
// 连接关闭时触发
}
其实就是在 xxx.com 上建立一个 长连接
,一般使用 socket.io
第三方库来代替使用
几种方式的特点
JSONP
仅支持 GET 方式,而且也不方便确认 JSONP 是否请求失败CORS
支持所有类型的 HTTP 方法,但是不兼容老版本浏览器postMessage
仅支持 GET 方式hash + iframe
仅支持 GET 方式以及 单向通信WebSockets
支持双向通信