跨域方法总结

733 阅读3分钟

设置跨域头

服务器设置跨域头,针对某个域名设置,origin那行字段是必须设置的,如果不设置,那么会报403的错误;服务器端 Access-Control-Allow-Credentials = true时,参数Access-Control-Allow-Origin 的值不能为 '*'

//表明允许跨域访问
Access-Control-Allow-Origin:上面origin的地址
Access-Control-Allow-Methods:POST,GET
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Origin,Content-Type,Accept,token,X-Requested-Wit

设置了跨域头了,那么什么样的请求服务器不会正确返回数据呢?答案是不按照约束的请求,比如:

  • Method只支持POST、GET,可是你用了DELETE
  • 比如需要一些身份认证的信息,而你没有设置XHR.withCredentials = true
  • 需要一些列举的头部信息,比如Origin、Content-Type,而你没有在请求头带上这个

JSONP

JSON WITH PADDING,只支持get请求,原理就是html标签的src属性是支持跨域的,但是要注意,浏览器跨域访问js、css、img等常规静态资源被同源策略许可,但iconfont字体文件(eot|otf|ttf|woff|svg)例外。JSONP的原理是,我们可以通过动态创建script,再请求一个带参网址实现跨域通信,比如数据内容为{code:1,data{count:200}},服务器会返回`callback({code:1,data{count:200}})给浏览器,而callback是会通过客户端的url传参给到服务器,客户端收到这样一段js代码,马上就执行了!jsonp实现思路:

var script = document.createElement('script');

script.type = 'text/javascript';
// 传参并指定回调执行函数为onBack
script.src = 'http://www.domain2.com:8080/login?user=admin&callback=onBack';
document.head.appendChild(script);
script.onload = function() { script.remove(); }

iframe跨域 + document.domain

此方案仅限主域相同,子域不同的跨域应用场景

  1. 父窗口www.domain.com/a.html
  2. 子窗口child.domain.com/b.html 两个都要执行document.domain = 'domain.com';

location.hash + iframe跨域

A域:a.html -> B域:b.html -> A域:c.html,a与b不同域只能通过hash值单向通信,b与c也不同域也只能单向通信,但c与a同域,所以c可通过parent.parent访问a页面所有对象

  1. a.html:(www.domain1.com/a.html)
    iframe引入b.html,传递hash值

  2. b.html:(www.domain2.com/b.html)
    收到hash值,然后查询b的数据,传到与a.html同域名的c.html

  3. c.html:(www.domain1.com/c.html)
    c拿到b的hash值,然后通过window.parent.parent访问a的回调函数

     // 监听b.html传来的hash值
     window.onhashchange = function () {
         // 再通过操作同域a.html的js回调,将结果传回
         window.parent.parent.onCallback('hello: ' + location.hash.replace('#user=', '')); 
         // onCallback是定义在a页面的一个函数
     };
    

window.name + iframe跨域

window.name属性的独特之处:name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)

  1. a域的html里定义一个iframe,src=需要请求的b域的地址
  2. b域执行代码window.name = 数据
  3. 然后a域的iframe onload完后,把iframe的src改成a域的,马上就可以访问window.name拿到的数据了,这一步是因为window.name只支持同域访问

postMessage + iframe跨域

postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题:

  • 页面和其打开的新窗口的数据传递
  • 多窗口之间消息传递
  • 页面与嵌套的iframe消息传递
  • 上面三个场景的跨域数据传递

1、a域

iframe.onload = function() {
    var data = {
        name: 'aym'
    };
    // 向domain2传送跨域数据
    iframe.contentWindow.postMessage(JSON.stringify(data), 'http://www.domain2.com');
};

// 接受domain2返回数据
window.addEventListener('message', function(e) {
    alert('data from domain2 ---> ' + e.data);
}, false);

2、b域

// 接收domain1的数据
window.addEventListener('message', function(e) {
    alert('data from domain1 ---> ' + e.data);

    var data = JSON.parse(e.data);
    if (data) {
        data.number = 16;

        // 处理后再发回domain1
        window.parent.postMessage(JSON.stringify(data), 'http://www.domain1.com');
    }
}, false);

反向代理

通俗点说就是发起一个a域的请求,让a域的服务器帮我们访问b域的数据,然后拿到之后,再返回给a域

websocket跨域

WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很好的实现