主题
跨域
协议 + 域名 + 端⼝
三者相同才为同源
前后端的跨域
Jsonp
js
// 前端
const script = document.createElement('script');
script.type = 'text/javascript';
// 接口?数据&回调函数
script.src = 'url?user=admin&callback=cb';
document.appendChild(script);
function cb(res){
JSON.parse(res);
}
// 后端,发送一个传入了数据的回调执行函数
cb(JSON.stringify({code: 1});
nginx 跨域
shell
# 简单例子
http {
# 监听 localhost:9000 ,"/" 则代理到 localhost:3000,"/api" 则代理到 localhost:8080
server {
listen 9000;
server_name localhost;
location / {
proxy_pass http://localhost:3000;
}
location /api/ {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
}
}
}
cors
GET
、POST
、HEAD
请求- 响应头中有一个
Access-Control-Allow-Origin
字段,用来记录可以访问该资源的域。 - 当浏览器收到这样的响应头信息之后,提取出
Access-Control-Allow-Origin
字段中的值,发现该值包含当前页面所在的域,就知道这个跨域是被允许的,因此就不再对前端的跨域请求进行限制
- 响应头中有一个
- 其他请求
- 客户端发送
OPTIONS
询问:Access-Control-Request-Method DELETE
- 服务器端响应
- 在发送跨域请求
- 客户端发送
WebSoocket
本身就没有同源限制
js
const ws = new WebSocket("wss://echo.websocket.org");
dev-server 代理跨域(用于开发时)
vue-cli:在项目根目录的
vue.config.js
中添加以下代码,开启 proxy,具体配置看查看 options
js
module.exports = {
devServer: {
proxy: {
// 代理跨域
'/api': {
target: 'http://localhost:8080', // 后端端口修改
secure: false
}
}, // 配置多个代理
}
};
create-react-app:只能代理一个(
/api
),可以在package.json
中加入如果 react 需要代理多个,可以使用库 http-proxy-middleware
json
{
"proxy": "http://localhost:8080"
}
vite:在
vite.config.js
中添加 proxy 规则
js
export default {
server: {
proxy: {
// 字符串简写写法
'/foo': 'http://localhost:4567/foo',
// 选项写法
'/api': {
target: 'http://jsonplaceholder.typicode.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
},
// 正则表达式写法
'^/fallback/.*': {
target: 'http://jsonplaceholder.typicode.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/fallback/, '')
}
}
}
}
可以直接模拟 cors 跨域
js
export default {
server: {
cors: true
}
}
前端间的跨域
domain + iframe
在主域相同,⼦域不同的跨域,可进行跨域
- 父窗口
html
<iframe id="iframe" src="http://www.domain.com/b.html"></iframe>
<script>
document.domain = "domain.com";
// 通过 bWindow 获取数据了
const bWindow = document.getElementById("iframe").contentWindow;
const data = bWindow.data;
// 通过 bDocument 给 b 窗口数据
const bDocument = document.getElementById("iframe").contentDocument;
bDocument.getElementById('p').innerText = "from A To B";
</script>
- 子窗口
html
<p id="p" style="display:none"></p>
<script>
document.domain = "domain.com";
// 传数据给 A 窗口,要和 A 协商好 key
window.data = "from B to A"
// 得到 A 给 B 的数据
const data2 = document.getElementById('p').innerText;
</script>
XDM
- 不会发送给服务端,是客户端和客户端之间的通讯
- 发送方使用
postMessage()
发送消息给接收方- 消息的字符串
- 接受源的字符串
js
window.postMessage('hello', 'https://www.baidu.com')
- 任何窗口都可以监听 message 事件,接受可能会传过来的信息。event 对象上有以下属性
- data:消息
- origin:发送消息的源
- source:发送源的 window 的代理,其上只有一个可用的方法——postMessage
js
window.addEventListener('message', event => {
if (event.origin === 'http://127.0.0.1') {
event.source.postMessage('received', 'http://127.0.0.1')
}
})
因为 message 事件可以接受所有域的消息,所以必须验证发送域是否是可信的域,才能使用其消息