解决跨域的8种最常用方法(附终极通用大招)
目录引言一、JSONP 跨域二、 iframe跨域2.1 window.name + iframe跨域2.2 location.hash + iframe跨域2.3 document.domain + iframe跨域三、postMessage 跨域四、nginx反向代理跨域五、nodejs 中间件代理跨域六、前端正向代理跨域七、WebSocket协议跨域引言上文中提到了cors 解决跨域的方法,
目录
2.3 document.domain + iframe跨域
引言
上文中提到了cors 解决跨域的方法,除此之外还有很多。
一、JSONP 跨域
jsonp的原理就是利用 <script>
标签没有跨域限制,通过<script>
标签src属性,发送带有callback参数的GET请求,服务端将接口返回数据拼凑到callback函数中,返回给浏览器,浏览器解析执行,从而前端拿到callback函数返回的数据。
JSONP的缺点:
- 具有局限性, 仅支持get方法
- 不安全,可能会遭受XSS攻击
二、 iframe跨域
2.1 window.name + iframe跨域
window.name属性的独特之处:name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持大小2MB的 name 值。
2.2 location.hash + iframe跨域
a欲与b跨域相互通信,通过中间页c来实现。 三个页面,不同域之间利用iframe的location.hash传值,相同域之间直接js访问来通信。
实现:A域:a.html -> B域:b.html -> A域:c.html,a与b不同域只能通过hash值单向通信,b与c也不同域也只能单向通信,但c与a同域,所以c可通过parent.parent访问a页面所有对象。
2.3 document.domain + iframe跨域
此方案仅限主域相同,子域不同的跨域应用场景。实现原理:两个页面都通过js强制设置document.domain为基础主域,实现同域。
三、postMessage 跨域
postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题的跨域:
- 页面和其打开的新窗口的数据传递
- 多窗口之间消息传递
- 页面与嵌套的iframe消息传递
用法:postMessage(data,origin)方法接受两个参数:
- data: html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以传参时最好用JSON.stringify()序列化。
- origin: 协议+主机+端口号,也可以设置为"*",表示可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。
四、nginx反向代理跨域
Nginx 是一款轻量级的 Web 服务器,也可以用于反向代理、负载平衡和 HTTP 缓存等。Nginx 使用异步事件驱动的方法来处理请求,是一款面向性能设计的 HTTP 服务器。通过Nginx配置一个代理服务器域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域访问。
五、nodejs 中间件代理跨域
通过启一个代理服务器,实现数据的转发,也可以通过设置cookieDomainRewrite参数修改响应头中cookie中域名,实现当前域的cookie写入,方便接口登录认证。
六、前端正向代理跨域
与反向代理跨域相对,在客户端设置了一个代理服务器,并且指定目标服务器,之后代理服务器向目标服务器转交请求并将获得的内容发送给客户端。本质上起到了对服务器隐藏客户端的目的。一般新建一个setupProxy.js进行配置
const proxy = require('http-proxy-middleware');
module.exports = function (app) {
app.use( proxy ('/api', {
target: url, /*这里写自己的代理地址*/
changeOrigin: true,
ws: true,
pathRewrite: {
'^/api': ''
},
}));
};
七、WebSocket协议跨域
WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很好的实现。
// 前端代码
<div>user input:<input type="text"></div>
<script src="https://cdn.bootcss.com/socket.io/2.2.0/socket.io.js"></script>
<script>
var socket = io('http://www.domain2.com:8080');
// 连接成功处理
socket.on('connect', function() {
// 监听服务端消息
socket.on('message', function(msg) {
console.log('data from server: ---> ' + msg);
});
// 监听服务端关闭
socket.on('disconnect', function() {
console.log('Server socket has closed.');
});
});
document.getElementsByTagName('input')[0].onblur = function() {
socket.send(this.value);
};
</script>
// 后台代码
var http = require('http');
var socket = require('socket.io');
// 启http服务
var server = http.createServer(function(req, res) {
res.writeHead(200, {
'Content-type': 'text/html'
});
res.end();
});
server.listen('8080');
console.log('Server is running at port 8080...');
// 监听socket连接
socket.listen(server).on('connection', function(client) {
// 接收信息
client.on('message', function(msg) {
client.send('hello:' + msg);
console.log('data from client: ---> ' + msg);
});
// 断开处理
client.on('disconnect', function() {
console.log('Client socket has closed.');
});
});
八、通用方法(仅限公司内网使用)
1. 在chrome://flags里搜索'same-site', 将下图 ‘SameSite by default cookies’ 项设置为disabled,重启chrome即可:
注意:浏览器的 Cookie 新增加了一个SameSite
属性,用来防止 CSRF 攻击和用户追踪。
它可以设置三个值:
- Strict
- Lax
- None
管控程度依次降低
2. 如果搜不到这个配置,说明当前chrome版本太高了,请参看下面的解决方案。
2.1 本地配置代理,将本地ip指向域名。(优点:不需要动chrome;缺点:配置有成本,和环境有耦合)
2.2 下载低版本的chrome,如 86.0.4240.75,下载地址。(优点:可以永久性避开问题;缺点:无法再体验新版chrome的功能)。安装后执行命令,禁止更新:
cd ~/Library/Google
sudo chown root:wheel GoogleSoftwareUpdate
更多推荐
所有评论(0)