多种跨域方式
了解同源
首先先了解一下,同源是指 protocol://hostName:port 三者相同,即便两个不同的域名指向同一个ip,也为非同源。
同源策略下,非同源之间有以下限制:
cookie, localStorage, indexDB 无法读取
Dom和JS对象无法获得
ajax 请求不能发送
JSONP
function jsonp ({url, params, callback}) {
return new Promise ((resolve, reject) => {
let script = document.createElement('script');
window[callback] = function(data) {
resolve(data);
document.body.removeChild(script);
}
params = {...params, callback};
let arr = [];
for (const key in params) {
arr.push(`${key}=${params[key]}`);
}
script.src = `${url}?${arr.join('&')}`;
document.body.appendChild(script);
});
}
jsonp({
url: 'http://localhost:8989/blog/',
params: {
name: 'kk'
},
callback: 'show'
}).then(data => {
console.log(data);
})
CORS
1. 设置withCredentials, 请求的时候带上cookie
let xhr = new XMLHttpRequest();
document.cookie = 'name=kk'; // cookie不能跨域
xhr.withCredentials = true; // 前端设置是否带cookie
xhr.open('PUT', 'http://localhost:3000/getData', true);
xhr.setRequestHeader('name', 'kk');
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
console.log(xhr.response);
console.log(xhr.getResponseHeader);
}
}
}
xhr.send();
2. 服务端做处理
let express = require('express')
let app = express()
let whitList = ['http://localhost:3000'] //设置白名单
app.use(function(req, res, next) {
let origin = req.headers.origin
if (whitList.includes(origin)) {
// 设置哪个源可以访问我
res.setHeader('Access-Control-Allow-Origin', origin)
// 允许携带哪个头访问我
res.setHeader('Access-Control-Allow-Headers', 'name')
// 允许哪个方法访问我
res.setHeader('Access-Control-Allow-Methods', 'PUT')
// 允许携带cookie
res.setHeader('Access-Control-Allow-Credentials', true)
// 预检的存活时间
res.setHeader('Access-Control-Max-Age', 6)
// 允许返回的头
res.setHeader('Access-Control-Expose-Headers', 'name')
if (req.method === 'OPTIONS') {
res.end() // OPTIONS请求不做任何处理
}
}
next()
})
app.put('/getData', function(req, res) {
console.log(req.headers)
res.setHeader('name', 'kkk1111')
res.end('我不爱你')
})
app.get('/getData', function(req, res) {
console.log(req.headers)
res.end('我不爱你')
})
app.use(express.static(__dirname))
app.listen(4000)
nginx
配置转发
postMessage
// a.html port: 3000
<!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>
<iframe src="http://localhost:4000/b.html" frameborder="0" id="frame" onload="load()"></iframe>
<script>
function load () {
let frame = document.getElementById('frame');
frame.contentWindow.postMessage('what u name?', 'http://localhost:4000');
window.onmessage = function(e) {
console.log(e.data);
}
}
</script>
</body>
</html>
// b.html port: 4000
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>b.html</title>
</head>
<body>
<script>
window.onmessage = function (e) {
console.log(e.data);
e.source.postMessage('kk', e.origin)
}
</script>
</body>
</html>

name
a和b是同域的 http://localhost:3000
c是独立的 http://localhost:4000
a获取c的数据
a先引用c c把值放到window.name,把a引用的地址改到b
// a.html
<body>
<iframe src="http://localhost:4000/c.html" frameborder="0" onload="load()" id="iframe"></iframe>
<script>
let first = true
function load() {
if(first){
let iframe = document.getElementById('iframe');
iframe.src = 'http://localhost:3000/b.html';
first = false;
}else{
console.log(iframe.contentWindow.name);
}
}
</script>
</body>
b.html 里面可以什么都不写
// c.html
<script>
window.name = 'kk';
</script>
hash
// a.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<!-- 路径后面的hash值可以用来通信 -->
<!-- 目的a想访问c -->
<!-- a给c传一个hash值 c收到hash值后 c把hash值传递给b b将结果放到a的hash值中-->
<iframe src="http://localhost:4000/c.html#whatuname?"></iframe>
<script>
window.onhashchange = function () {
console.log(location.hash);
}
</script>
</body>
</html>
// b.html
<script>
window.parent.parent.location.hash = location.hash
</script>
// c.html
<script>
console.log(location.hash);
let iframe = document.createElement('iframe');
iframe.src = 'http://localhost:3000/b.html#kk';
document.body.appendChild(iframe);
</script>
domain
该方式只适用于二级域名相同的情况下
// a.html
<body>
<h1>Hi, there is A Page</h1>
<iframe
id="iframe"
src="http://test.com:2333/b.html"
frameborder="0"
onload="load()"
></iframe>
<script>
document.domain = "test.com";
function load() {
let iframe = document.getElementById('iframe');
console.log(iframe.contentWindow.data); // This is b html content.
}
</script>
// b.html
<body>
<h1>Hi, there is B Page</h1>
<script>
document.domain = 'test.com';
var data = "This is b html content.";
</script>
</body>
websocket
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
// 高级api 不兼容 socket.io(一般使用它)
let socket = new WebSocket('ws://localhost:3000');
socket.onopen = function () {
socket.send('what u name?');
}
socket.onmessage = function (e) {
console.log(e)
console.log(e.data);
}
</script>
</body>
</html>
let express = require('express');
let app = express();
let WebSocket = require('ws');
let wss = new WebSocket.Server({
port:3000
});
wss.on('connection',function(ws) {
ws.on('message', function (data) {
console.log(data);
ws.send('kk')
});
})
// app.listen(3000);