同源策略
协议 域名 端口
常见的跨域问题
cookie LocalStorage DOM元素 iframe ajax
实现跨域的方法
- jsonp
- cors
- postMessage
- document.domain
- window.name
- location.hash
- http-proxy
- nginx
- websocket
jsonp
function jsonp({ url, params, cb }) {
return new Promise((resolve, reject) => {
window[cb] = function(data) {
resolve(data);
document.body.removeChild(script);
};
let script = document.cerateElement("script");
params = { ...params, cb };
const queryStr = Object.keys(params)
.map(key => {
return `${key}=${params[key]}`;
})
.join("&");
script.src = `${url}?${queryStr}`;
document.body.appendChild(script);
});
}
缺点: 只能发送get请求; 容易受到xss攻击
cors
// express Server
const express = require("express");
const app = express();
app.use(express.static(__dirname));
const whitList = [
"http://localhost:4000",
"http://localhost:5000",
"http://localhost:6000"
];
app.use(function(req, res, next) {
let origin = req.headers.origin;
if (whitList.includes(origin)) {
// 设置允许跨域
res.setHeader("Access-Control-Allow_origin", true);
res.setHeader("Access-Control-Allow-Headers", "name"); // 允许携带哪些字段的请求头访问
res.setHeader("Access-Control-Allow-Methods", "post"); // 允许的请求方法
res.setHeader("Access-Control-Allow-Credentials", true); // 是否可以携带cookie
res.setHeader("Access-Control-Allow-Expose-Headers", "name,token"); // 允许返回的请求头信息
res.setHeader("Access-Control-Allow-Max-Age", 5000); // 预检的有效时间
if (req.method === "OPTIONS") {
// put 请求会发送两次
res.end();
}
}
next();
});
app.get("/getList", (req, res) => {
const { id } = req.query;
const body = {};
res.end(body);
});
app.listen(300);
// AJAX
document.cookie = "token=kkhga2019";
xhr.withCredentials = true; // 携带cookie信息
let xhr = new XMLHttpRequest();
xhr.open("GET", "http://localhost:4000", true);
xhr.setRequestHeader("name", "appname");
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if ((xhr.status >= 200 && xhr.status <= 300) || xhr.status === 304) {
const res = xhr.response;
}
}
};
缺点:
postMessage 页面之间的跨域通讯
<!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>
<iframe
src="http://localhsot:4000/b.html"
frameborder="0"
id="frame"
onload="load()"
></iframe>
<!-- a.html -->
<script>
function load() {
let frame = document.getElementById("frame");
frame.contentWindow.postMessage(
// 发
"getList",
"http://localhost:4000" // origin
);
// 收
window.onmessage = function(e) {
// e.data
};
}
</script>
<!-- b.html -->
<script>
window.onmessage = function(e) {
e.source.postMessage(data, e.origin);
};
</script>
</body>
</html>
window.name
<!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>
<iframe
src="http://localhsot:4000/b.html"
frameborder="0"
onload="load()"
id="iframe"
></iframe>
<!-- a.html -->
<script>
let first = true;
function load() {
if (first) {
let iframe = document.getElementById("iframe");
iframe.src = "http://localhost:3000/b.html";
first = false;
} else {
const data = iframe.contentWindow.name;
}
}
</script>
<!-- b.html -->
<script>
window.name = data;
</script>
</body>
</html>
location.hash
<!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可以用来通讯 -->
<iframe
src="http://localhsot:4000/b.html#id=no101"
frameborder="0"
onload="load()"
id="iframe"
></iframe>
<!-- a.html -->
<script>
let first = true;
function load() {
let iframe = document.getElementById("iframe");
iframe.src = "http://localhost:3000/b.html";
}
widnow.onhashchange = function() {};
</script>
<!-- b.html -->
<script></script>
<!-- c.html -->
<script></script>
</body>
</html>
document.domain
<!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>
<!-- 一级域名 二级域名 -->
<iframe
src="http://b.baidu.com/b.html"
frameborder="0"
onload="load()"
id="iframe"
></iframe>
<!-- a.html http://a.baidu.com -->
<script>
document.domane = "a.baidu.com";
function load() {
let iframe = document.getElementById("iframe");
const a = iframe.contentWindow.a;
}
</script>
<!-- b.html -->
<script>
ocument.domane = "a.baidu.com";
</script>
</body>
</html>
websocket
// websocket socket.io(解决兼容的库)
const socket = new WebSocket("ws://localhost:3000");
socket.onopen = function() {
socket.send(data);
};
socket.onmessage = function(e) {
const data = e.data;
};
// server
const express = requrie("express");
const app = express();
const WebSocket = require("ws");
const wss = new WebSocket.Server({ port: 3000 });
wss.on("connection", function(ws) {
ws.on("message", function(data) {
const data = data;
ws.send(body);
});
});