文章目录
跨域的发生
浏览器跨域的问题来源于同源策略,
说明 | 举例 | 是否允许通信 |
---|---|---|
同一域名,不同文件或路径 | http://www.domain.com/a.js http://www.domain.com/b.js | 支持 |
同一域名,不同端口 | http://www.domain.com:8000/ http://www.domain.com | 不支持 |
同一域名,不同协议 | http://www.domain.com https://www.domain.com | 不支持 |
域名和域名对应相同ip | http://www.domain.com http://192.168.2.1 | 不支持 |
主域相同,子域不同 | http://www.domain.com http://domain.com | 不支持 |
不同域名 | http://www.b.com http://www.a.com | 不支持 |
怎么解决跨域
跨域的解决办法有很多种
这里推荐两种:nginx反向代理、cors(跨域资源共享)
websocket协议
websocket协议是一种全双工通信协议,并且该协议被允许跨域请求。
window.postMessage
window对象可以获取其他窗口的一个引用,比如iframe的contentWindow属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames。
<body>
<button onclick="go()">go</button>
<button onclick="send()">send</button>
</body>
<script>
// postmessage 使用8081端口打开
var a
function go() {
a = window.open("http://192.168.1.6:8080/p2.html")
send()
}
function send(){
a.postMessage(2,"http://192.168.1.6:8080/p2.html")
}
window.addEventListener("message",function(event){
console.log(event.data) // 3
},false)
</script>
<script>
// p2 使用8080端口
var targetWindow = window.opener
window.addEventListener("message",function(event){
console.log(event.data,"收到") //2
targetWindow.postMessage(event.data + 1,event.origin)
},false)
</script>
此时可以使用postMessage方法向其它页面传递消息
document.domain + iframe
当主域相同子域不同时可以使用这个方式,两个域都通过js强制设置document.domain为基础主域,就实现了两页面之间相互访问变量
window.location.hash + iframe
在这个实现方式中,a,c是同域,b是另一个域,整体实现方式是 a →b →c→a,a到b到c之间的通讯可以依赖hash值的变化,iframe页面监听hash值变化来获取值,c到a因为是同域可以使用window.parent.parent实现c访问a的回调方法
window.name + iframe
这个方案主要是利用window.name的特性,name的值在不同页面,不同域加载后依然存在,并且可以支持2M的值(iE、firefox支持32M,听说啊)。利用iframe加载一个跨域文件,加载完成后设置window.name之后再重定向到一个同域的页面,同域的页面即可通信获得window.name携带的参数
nginx代理
因为同源策略限制的是浏览器的请求,所以在服务器端即使跨域也没有影响,利用服务器访问对应的资源统一通过代理返回即可解决跨域
这个方式是利用nginx反向代理的能力,将不同域之间的请求归并到一个域下,首先需要安装nginx,然后配置两个域的代理,都使用同一端口 ,但是路径不同。比如:3000/a指向实际业务的1000端口,:3000/b指向实际业务的4000的端口
cors跨域资源共享
服务端设置Access-Control-Allow-Origin,允许资源被跨域访问。这种方式对于不携带cookie的请求是很方便的,但是如果需要携带cookie可以参考nginx代理
node代理
利用node服务做代理实现跨域请求
JsonP解决跨域
这种方式是利用浏览器在请求js,css,img等静态资源时是被浏览器允许访问跨域资源的(因为可能需要静态资源部署在资源服务器),基于此原理,可以在需要请求的时候使用js添加script标签,并设置回调函数。在服务端返回对应script标签的资源时将参数携带在回调函数中
<script>
var script = document.createElement('script');
script.type = 'text/javascript';
// 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数
script.src = 'http://www.domain2.com:8080/login?user=admin&callback=handleCallback';
document.head.appendChild(script);
// 回调执行函数
function handleCallback(res) {
alert(JSON.stringify(res));
}
</script>
后端返回
handleCallback({"status": true, "user": "admin"})
跨域时请求
简单请求不会触发预检请求Options Preflight request