跨域解决方案合集

浏览器的同源策略会导致跨域,这里同源策略又分为以下两种
1. DOM同源策略:禁止对不同源页面DOM进行操作。这里主要场景是iframe跨域的情况,不同域名的iframe是限制互相访问的。
2. XmlHttpRequest同源策略:禁止使用XHR对象向不同源的服务器地址发起HTTP请求。
只要协议、域名、端口有任何一个不同,都被当作是不同的域,之间的请求就是跨域操作。

为什么要有跨域:安全
https://zhuanlan.zhihu.com/p/28562290

解决方式:

针对DOM不同源:
1. document.domain
2. Location.hash
3. postMessage

针对XmlHttpRequest不同源:
1. 跨域资源共享 CORS
* http://www.ruanyifeng.com/blog/2016/04/cors.html
* 实现CORS通信的关键是服务器,只要服务器实现了CORS接口,就可以实现跨源通信
* CORS请求分为:简单请求 & 非简单请求
* 服务器相应中CORS相关字段都带 Access-Control- 开头
* 客户端中 withCredentials 属性
2. jsonp
* 只支持GET请求,支持老式浏览器,可以向不支持CORS的网络请求数据
3. 服务器代理

Jsonp:

JSONP是一种非正式传输协议,该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。JSONP只能是get请求,script也是一种get请求,利用script标签没有跨域限制的特性来达到与第三方通讯的目的,第三方产生的响应为json数据的包装(jsonp,json padding),即后端输出的response text必须符合js语法

//方式1
//这种方式无法对请求进行错误处理
var script = document.createElement("script");
script.src = "https://api.douban.com/v2/book/search?q=javascript&count=1&callback=handleResponse";
document.body.insertBefore(script, document.body.firstChild);

//方式2
$.ajax({
    url: 'https://api.douban.com/v2/book/search?callback=handleResponse',
    data: {
        q: 'javascript',
        count: 1
    },
    jsonp: 'callback',//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback)
    dataType: 'jsonp',//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以不写,jQuery会把数据拿出来放到success函数的参数里
    jsonpCallback: 'handleResponse',
    success (data){
        console.log(data);
    },
    error (XMLHttpRequest, textStatus, errorThrown){
        console.error(XMLHttpRequest, textStatus, errorThrown)
    }
});

//方式3(仅接口是.json后缀才可以跨域,即访问远程json文件)
$.getJSON("GetUserbyName.aspx?name=ww&callback=?",
    function(date){
        //....
    }
)
  1. html标签的src属性没有同源限制(支持跨域),浏览器解析script标签时,会自动下载src属性值(url)指向的资源;
  2. script标签指向的资源文件被下载后,其中的内容会被立即执行;服务器端的程序会解析src属性值中的url传递的参数,根据这些参数针对性返回一个/多个函数调用表达式,这些函数调用表达式的参数就是客户端跨域想得到的数据;
  3. 服务器生成、返回的文件中,表达式调用的函数是已经在本地提前定义好的,而参数就是希望从跨域服务器拿到的数据。
  4. 字面的script标签可以,动态添加到dom树中的script也可以,后者更方便绑定事件。
  5. img link iframe 等元素都可以发送跨域请求
  6. 只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。

document.domain

用document.domain来指定域有局限性,也就是一级域名一致才可以

www.sojson.com 下指到 sojson.com 是可以的。
icp.sojson.com 下指到 sojson.com 是可以的。

www.sojson.com 下指到 www.baidu.com 是不行的。
sojson.com 指到 baidu.com 还是不行的。

在需要通信的两个域中都写下如下代码:

if(document.domain != 'sojson.com'){
    document.domain = 'sojson.com';
}

保证一致即可

一级域名  有的人叫根域名,如:sojson.com、baidu.com、sina.com、sina.com.cn、sina.cn.net 等等。

二级域名  是指增加了一级,包括www。如:www.sojson.com、icp.sojson.com、zhidao.baidu.com、www.baidu.com  等等

document.domain 描述对象
document.domain 只能修改为一级域名一致的域名

document.domain

用document.domain来指定域有局限性,也就是一级域名一致才可以

    www.sojson.com  下指到 sojson.com 是可以的。
    icp.sojson.com  下指到 sojson.com 是可以的。

    www.sojson.com  下指到 www.baidu.com  是不行的。
    sojson.com  指到 baidu.com  还是不行的。

在需要通信的两个域中都写下如下代码:

if(document.domain != 'sojson.com'){
    document.domain = 'sojson.com';
}

保证一致即可

一级域名  有的人叫根域名,如:sojson.com、baidu.com、sina.com、sina.com.cn、sina.cn.net 等等。

二级域名  是指增加了一级,包括www。如:www.sojson.com、icp.sojson.com、zhidao.baidu.com、www.baidu.com  等等

location.hash

通过把数据写在url的#号后面来传递数据。a.com 里的页面 a1.html嵌套 b.com 的 b1.html,b1.html 修改 parent.hash,a1.html 监听 hashchange 来实现。(ie、chrome的安全机制无法修改parent.location.hash,所以要利用一个中间的 a.com 域下的代理iframe,即在 b1.html 中增加一个 iframe,src为 a.com 域下的页面)

利用hash跨域,数据直接暴露在了url中,数据容量和类型都有限

//a1.html
function startRequest(){  
    var ifr = document.createElement('iframe');  
    ifr.style.display = 'none';  
    ifr.src = 'http://www.cnblogs.com/lab/cscript/cs2.html#paramdo';  
    document.body.appendChild(ifr);  
}  


function checkHash() {  
    try {  
        var data = location.hash ? location.hash.substring(1) : '';  
        if (console.log) {  
            console.log('Now the data is '+data);  
        }  
    } catch(e) {};  
}  
setInterval(checkHash, 2000);


//b1.html 模拟一个简单的参数处理操作  
switch(location.hash){  
    case '#paramdo':  
        callBack();  
        break;  
    case '#paramset':  
        //do something……  
        break;  
}


function callBack(){  
    try {  
        parent.location.hash = 'somedata';  
    } catch (e) {  
        // ie、chrome的安全机制无法修改parent.location.hash,  
        // 所以要利用一个中间的cnblogs域下的代理iframe  
        var ifrproxy = document.createElement('iframe');  
        ifrproxy.style.display = 'none';  
        ifrproxy.src = 'http://a.com/test/cscript/cs3.html#somedata';    // 注意该文件在"a.com"域下  
        document.body.appendChild(ifrproxy);  
    }  
}

//a2.html
//因为parent.parent和自身属于同一个域,所以可以改变其location.hash的值  
parent.parent.location.hash = self.location.hash.substring(1);

postmessage

window, localStorage & sessionStorage 都是同一域名下的本地存储,不能跨域存储。
https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage

猜你喜欢

转载自blog.csdn.net/ming_221/article/details/80105813