跨域
1. jsonp
jsonp实现跨域的原理就是利用一些可以请求资源的标签,像script
,img
这类的标签它们请求资源是没有域的限制的。
实现
客户端
<script>
function myFunction(data) {
console.log(data);
}
</script>
<script src="http://localhost:3000/test?callback=myFunction"></script>
服务器(返回的函数调用以字符串形式浏览器会自行解析)
const express = require('express')
const app = express()
app.get('/test', (req, res) => {
const { callback } = req.query
const data = {
data: '这是服务中返回的数据'
}
res.send(callback + '(' + JSON.stringify(data) + ')')
})
app.listen(3000)
console.log('服务启动');
2. CORS
cors跨域请求又分为简单请求和非简单请求,而非简单请求是指对对服务器有特殊要求的这里不做演示,只需要知道非简单简单请求会在正式通信之前,增加一次HT TP查询请求,称为"预检"请求(preflight)
对于一个简单请求,浏览器会直接发一个cors请求,即在请求的头部字段加一个源origin
字段,写明此次请求来源。
服务器则会根据信息,判断是否同意客户端的此次请求,其响应字段设置如下
- Access-Control-Allow-Origin:必选,它的值要么是请求时Origin字段的值,要么是一个*,*表示允许全部。
- Access-Control-Allow-Credentials :可选,值为boolean。表示是否允许发送cookie
- Access-Control-Expose-Headers:可选
### 实现
客户端
<script>
const xhr = new XMLHttpRequest();
const url = 'http://localhost:3000/test'; // 请求的3000端口获取数据
xhr.open('GET', url); // 与3000端口建立一个连接
xhr.send(null);
xhr.onload = () => {
console.log(xhr.responseText);
}
</script>
服务器
const express = require('express')
const app = express()
app.get('/test', (req, res) => {
res.set('Access-Control-Allow-Origin', 'http://127.0.0.1:5501');//允许源
res.send('服务器消息')
})
app.listen(3000)
console.log('服务启动');
3. document.domain+iframe
此跨域方案有很大的限制,它的应用场景是在主域相同,子域不同的情况下使用。
原理:两端页面利用 document.domain设置成同一个基础主域
实现
a(父)页面
<iframe src="http://b.domain.cn/b.html" id="iframe" style="display: none;" onload="show()"></iframe>
<script>
document.domain = 'domain.cn'; //设置成主域
const data = 'data'
</script>
b(子)页面
<script>
document.domain = 'domain.cn'; //设置成主域
console.log(`来自a.html ${window.parent.data}`);
</script>
4. window.name+iframe
将传输的值放到window.name中
注意,直接去不同域页面上window.name的值是不被允许的,需要用一个同域页面做代理。
实现
3000端口中
a.html
<iframe src="http://127.0.0.1:3001/b.html" id="iframe" style="display: none;"></iframe>
<script>
let count = 0;
// onload事件会触发两次,第二次才是我们要的数据
iframe.onload = function() {
if (count == 0) {
iframe.src = 'http://localhost:3000/proxy.html'; //先指同源
count++;
return;
}
console.log(iframe.contentWindow.name);
}
proxy.html(空白即可仅作为中转)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<p>proxy</p>
</body>
</html>
3001端口中
b.html
<body>
<script>
//给a的数据在这里面
window.name = 'gongxiaobai'
</script>
</body>
5. location.hash+iframe
利用url中的hash进行传值,和上面6中一样。a与b通信同样需要借助一个中间人处理
实现
3000端口
a.html
<iframe id="iframe" src="http://127.0.0.1:3001/b.html#aaaa" style="display:none;"></iframe>
<script>
function checkHash(res) {
console.log(res);
}
//传过来的值是放在hash上了,故监听hash值的变化
window.onhashchange = function() {
checkHash(location.hash.slice(1))
}
</script>
c.html(中间人)
parent.parent.location.hash = self.location.hash.substring(1);
3001端口
b.html
var message = 'bbbbb'
if (location.hash === '#aaaa') {
var ifrproxy = document.createElement('iframe');
ifrproxy.style.display = 'none';
ifrproxy.src = 'http://localhost:3000/c.html#' + message;
document.body.appendChild(ifrproxy);
}
6. postMessage+iframe
这是一个h5的api,它同样也可以实现跨域。既然是一个api,那么一般就有参数。 postMessage(data,origin)
这个api方法有两个参数,1为传输的数据(基本上任意类型)最好转成json字符串毕竟跨域对面的语言不知是啥,2为源(协议+主机+端口)可为*
、同源设为/
实现
3000端口
a.html
<iframe id="iframe" src="http://127.0.0.1:3001/b.html" style="display:none;"></iframe>
<script>
iframe.onload = function() {
const data = {
name: 'a的信息'
};
// 向b传送跨域数据
iframe.contentWindow.postMessage(JSON.stringify(data), 'http://127.0.0.1:3001');
};
</script>
3001端口
b.html
<script>
// 接收a的数据
window.addEventListener('message', function(e) {
console.log(e.data); //a的数据
}, false);
</script>
7. WebSocket
WebSocket protocol 同样来自h5,它是h5的一个新协议。它是全双工通信喔,不过使用WebSocket 的API不方便故一般均会使用Socket.io,Socket.io对于WebSocket 有很好的封装。
实现
客户端
<script>
var io = io.connect('http://127.0.0.1:3000');
io.on('serive', function(data) {
console.log(data);
});
</script>
服务器
const app = require('express')();
const server = require('http').createServer();
const io = require('socket.io')(server);
io.on('connection', function(client) {
client.emit('serive', 'aaaa');
});
server.listen(3000)
console.log('ok');
9. 各种代理
使用这个实现的原理:服务器与服务器之间是没有跨域问题的,故可以用中间的一个代理向目标浏览器发送请求
代理有以下几种方式,这里不做演示了
-
http-proxy-middleware
-
打包工具中
-
nginx