同源策略
协议 域名 端口 三者都相同时满足: 同域
需要跨域:
cookie
LocalStorage
Dom(iframe)
ajax
跨域方案
jsonp
只能发送get请求,不支持post put delete
不安全 xss攻击
一般不采用了
代码实现:
<script>
function jsonp({url, params, cb}) {
return new Promise((resolve, reject) => {
let script = document.createElement('script');
window(cb) = function (data) {
resolve(data);
document.body.removeChild(script);
}
params = {...params, cb}
let arrs = [];
for(let key in params) {
arrs.push(`${key}=${params[key]}`);
}
script.src = `${url}?${arrs.join('&')}`;
document.body.appendChild(script);
});
}
jsonp({
url: 'http://localhost:3000/say',
params: {wd: 'how are you'},
cb: 'show'
}).then(data => {
console.log(data);
})
</script>
后端express:
安装依赖
npm install express
server.js代码
let express = require('express');
let app = express();
app.get('/say', function(req, res) {
let {wd, cb} = req.query;
console.log(wd);
res.end(`${cb}('i am fine')`);
})
app.listen(3000);
cors
最常用,比较安全
前端ajax:
// get 请求
let xhr = new XMLHttpRequest;
xhr.open('GET', 'http://localhost:4000/getData', true);
xhr.setRequestHeader('name', 'i am iron man');
xhr.onreadystatechange = function() {
if(xhr.readyState === 4) {
if(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
console.log(xhr.response);
}
}
}
// put 请求
let xhr = new XMLHttpRequest;
document.cookie = 'name=ironman';
xhr.withCredentials = true;
xhr.open('PUT', 'http://localhost:4000/getData', true);
xhr.setRequestHeader('name', 'i am iron man');
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('name')); // 需要后端设置允许 Expose-Headers
}
}
}
xhr.send();
后端express同上
// server1:
let express = require('express');
let app = express();
app.use(express.static(__dirname));
app.listen(3000);
// server2:
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', 6000);
// 允许前端获取哪个头
res.setHeader('Access-Control-Expose-Headers', 'name');
if(req.method === 'OPTIONS') {
res.end(); // put请求时多发了一次测试请求,设置OPTIONS请求不做任何处理,不稳定
}
}
next();
})
app.get('/getData', function(req, res) {
res.end('i am fine');
})
app.put('/getData', function(req, res) {
res,setHeader('name', 'captain');
res.end('i am fine');
})
app.use(express.static(__dirname));
app.listen(4000);
postMessage
实现两个页面通信而不是数据通信
前端部分
<!-- server1 对应的页面a -->
<iframe id="frame" src="http://localhost:4000/b.html" frameborder="0" onload="load()">
</iframe>
<script>
function load() {
let frame = document.getElementById('frame');
frame.contentWindow.postMessage('how are you', 'http://localhost:4000');
window.onmessage = function(e) {
console.log(e.data);
}
}
</script>
<!-- server2 对应的页面b -->
<script>
window.onmessage = function(e) {
console.log(e.data);
e.source.postMessage('i am fine', e.origin);
}
</script>
后端express同上
// server1:
let express = require('express');
let app = express();
app.use(express.static(__dirname));
app.listen(3000);
// server2:
let express = require('express');
let app = express();
app.use(express.static(__dirname));
app.listen(4000);
window.name
前端代码:
<!-- 页面a -->
<!-- a和b是同域的:3000
c是独立的:4000
a要获取c的数据
a先引用c c把值放到window.name,再把a引用的地址改到b -->
<iframe id="iframe" src="http://localhost:4000/c.html" frameborder="0" onload="load()">
</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>
<!-- 页面c -->
<script>
window.name = 'i am fine'
</script>
后端express同上:
// server1:
let express = require('express');
let app = express();
app.use(express.static(__dirname));
app.listen(3000);
// server2:
let express = require('express');
let app = express();
app.use(express.static(__dirname));
app.listen(4000);
location.hash
路径后面的hash值可以用来通信
前端代码:
<!-- 页面设定同上,a访问c,a给c传一个hash值,c收到hash值之后,把hash值传递给b,b将结果放到a的hash值中 -->
<!-- 页面a -->
<iframe id="iframe" src="http://localhost:4000/c.html#howareyou" onload="load()">
</iframe>
<script>
window.onhashchange = function() {
console.log(location.hash);
}
</script>
<!-- 页面c -->
<script>
console.log(location.hash);
let iframe = document.createElement('iframe');
iframe.src = 'http://localhost:3000/b.html#iamfine';
document.body.appendChild(iframe);
</script>
<!-- 页面b -->
<script>
window.parent.parent.loaction.hash = location.hash;
</script>
后端同上:
// server1:
let express = require('express');
let app = express();
app.use(express.static(__dirname));
app.listen(3000);
// server2:
let express = require('express');
let app = express();
app.use(express.static(__dirname));
app.listen(4000);
document.domain
两个页面是一级域名和二级域名的关系
前端代码:
<!-- 页面a:http://a.ky1.cn:3000/a.html -->
<iframe id="frame" src="http://b.ky1.cn:3000/b.html" frameborder="0" onload="load()">
</iframe>
<script>
document.domain = 'ky1.cn';
function load() {
console.log(frame.contentWindow.a);
}
</script>
<!-- 页面b -->
<script>
document.domain = 'ky1.cn';
var a = 100;
</script>
后端同上:
// server1:
let express = require('express');
let app = express();
app.use(express.static(__dirname));
app.listen(3000);
// server2:
let express = require('express');
let app = express();
app.use(express.static(__dirname));
app.listen(4000);
nginx
nginx.org 下载安装
json文件夹新建文件 a.json
{
"name": "跨域方案"
}
conf文件夹 nginx.conf文件
location ~.*\.json {
root json;
add_header "Access-Control-Allow-Origin" "*";
}
前端代码:
let xhr = new XMLHttpRequest;
xhr.open('get', 'http://localhost/a.json', true);
xhr.onreadystatechange = function() {
if(xhr.readyState === 4) {
if(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
console.log(xhr.response);
}
}
}
xhr.send();
后端同上:
let express = require('express');
let app = express();
app.use(express.static(__dirname));
app.listen(3000);
websocket
高级api 不兼容 一般使用socket.io
前端代码:
let socket = new WebSocket('ws://localhost:3000');
socket.onopen = function() {
socket.send('how are you');
}
socket.onmessage = function(e) {
console.log(e.data);
}
后端express同上:
// server:
// 安装依赖 npm install ws
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('i am fine');
})
})