浅谈浏览器端JavaScript跨域解决方法

由于平安的缘由,浏览器做了许多方面的事情,由此也就引入了一系列的跨域题目,需要注重的是:

跨域并不是浏览器限定了提议跨站要求,而是跨站要求能够平常提议,然则返回效果被浏览器阻拦了。最好的例子是 crsf 跨站进击道理,要求是发送到了后端服务器不管是不是跨域!注重:有些浏览器不许可从HTTPS的域跨域接见HTTP,比方Chrome和Firefox,这些浏览器在要求还未发出的时刻就会阻拦要求,这是一个惯例

1. JSONP

JSONP的全称是 “JSON With Padding”, 词面意义上明白就是 “添补式的JSON”。它不是一个新颖的东西,隶属于 JSON 的一种运用要领,或许说是一种运用形式,能够处置惩罚一些罕见的浏览器端网页跨域题目。

正如他的称号一样,它是指被包括在挪用函数中的JSON,比方如许:

callback({"Name": "小明", "Id" : 1823, "Rank": 7})

由于 jQuery 的一些缘由,使得 JSONP 经常与 Ajax 殽杂。实际上,他们没有任何关系。

由于浏览器的同源战略,使得在网页端涌现了这个“跨域”的题目,但是我们发明,一切的 src 属性并没有遭到相干的限定,比方 img / script 等。

JSONP 的道理就要从 script 提及。script 能够实行其他域的js 函数,比方如许:

a.html
...
<script>
  function callback(data) {
    console.log(data.url)
  }
</script>

<script src='b.js'></script>
...


b.js
callback({url: 'http://www.rccoder.net'})

明显,上面的代码是能够实行的,而且能够在console内里输出http://www.rccoder.net

应用这一点,假如b.js内里的内容不是牢固的,而是依据一些东西自动天生的, 嗯,这就是JSONP的重要道理了。回调函数+数据就是 JSON With Padding 了,回调函数用来相应应该在页面中挪用的函数,数据则用来传入要实行的回调函数。

至于这个数据是怎样发生的,说粗暴点不过就是字符串拼接了。

简朴总结一下: Ajax 是应用 XMLHTTPRequest 来要求数据的,而它是不能要求差别域上的数据的。然则,在页面上援用差别域的 js 文件倒是没有任何题目标,如许,应用异步的加载,要求一个 js 文件,而这个文件的内容是动态天生的(背景言语字符串拼接出来的),内里包括的是 JSON With Padding(回调函数+数据),之前写的谁人函数就由于新加载进来的这段动态天生的 js 而实行,也就是猎取到了他要猎取的数据。

反复一下,在一个页面中,a.html如许写,获得 UserId 为 1823 的信息:

a.html

...
src="http://server2.example.com/RetrieveUser?UserId=1823&callback=parseResponse">
...

要求这个地点会获得一个能够实行的 JavaScript。比方会获得:

  parseResponse({"Name": "小明", "Id" : 1823, "Rank": 7})

如许,a.html内里的 parseResponse() 这个函数就可以实行而且获得数据了。

等等,jQuery究竟做了什么:

jQuery 让 JSONP 的运用API和Ajax的如出一辙:

$.ajax({
  method: 'jsonp',
  url: 'http://server2.example.com/RetrieveUser?UserId=1823',
  success: function(data) {
    console.log(data)
  } 
})

之所以能够如许是由于 jQuery 在背地倾泻了心血,它会在实行的时刻天生函数替代callback=dosomthing ,然后猎取到数据以后销毁掉这个函数,起到一个暂时的代办器作用,如许就拿到了数据。

JSONP 的后话

JSONP的这类完成体式格局不受同源战略的影响,兼容性也很好;然则它之支撑 GET 体式格局的清晰,只支撑 HTTP 要求这类特别的状况,关于两个差别域之间两个页面的相互挪用也是无计可施。

2. CORS

XMLHttpRequest 的同源战略看起来是云云的变态,即使是统一个公司的产物,也不可能完整在统一个域上面。还好,收集设想者在设想的时刻考略到了这一点,能够在服务器端举行一些定义,许可部份收集接见。

CORS 的全称是 Cross-Origin Resource Sharing,即跨域资源同享。他的道理就是运用自定义的 HTTP 头部,让服务器与浏览器举行沟通,重假如经由过程设置相应头的 Access-Control-Allow-Origin 来到达目标的。如许,XMLHttpRequest 就可以跨域了。

值得注重的是,平常状况下的 XMLHttpRequest 是只发送一次要求的,然则跨域题目下许多是会发送两次的要求(预发送)。

越发细致的内容能够拜见:

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

CORS 的后话:

相比之下,CORS 就支撑一切范例的 HTTP 要求了,然则在兼容上面,每每一些老的浏览器并不支撑 CORS。

Desktop:

浏览器版本
Chrome4
Firefox (Gecko)3.5
Internet Explorer8 (via XDomainReques) 10
Opera12
Safari4

Mobile:

装备版本
Android2.1
Chrome for Androidyes
Firefox Mobile (Gecko)yes
IE Mobile?
Opera Mobile12
Safari Mobile3.2

3. window.name

window.name 在一个窗口(标签)的生命周期以内是同享的,应用这点就可以够传输一些数据。

除此之外,连系 iframe 还能完成越发壮大的功用:

需要3个文件: a/proxy/b

a.html

<script type="text/javascript">
    var state = 0, 
    iframe = document.createElement('iframe'),
    loadfn = function() {
        if (state === 1) {
            var data = iframe.contentWindow.name;    // 读取数据
            alert(data);    //弹出'I was there!'
        } else if (state === 0) {
            state = 1;
            iframe.contentWindow.location = "http://a.com/proxy.html";    // 设置的代办文件
        }  
    };
    iframe.src = 'http://b.com/b.html';
    if (iframe.attachEvent) {
        iframe.attachEvent('onload', loadfn);
    } else {
        iframe.onload  = loadfn;
    }
    document.body.appendChild(iframe);
</script>
b.html

<script type="text/javascript">
    window.name = 'I was there!';    // 这里是要传输的数据,大小平常为2M,IE和firefox下能够大至32M摆布
                                     // 数据格式能够自定义,如json、字符串
</script>

proxy 是一个代办文件,空的就可以够,需要和 a 在统一域下

4. document.domain

在差别的子域 + iframe交互的时刻,猎取到别的一个 iframe 的 window对象是没有题目标,然则猎取到的这个window的要领和属性大多数都是不能运用的。

这类征象能够借助document.domain 来处置惩罚。

example.com

<iframe id='i' src="1.example.com" onload="do()"></iframe>
<script>
  document.domain = 'example.com';
  document.getElementById("i").contentWindow;
</script>
1.example.com

<script>
  document.domain = 'example.com';  
</script>

如许,就可以够处置惩罚题目了。值得注重的是:document.domain 的设置是有限定的,只能设置为页面本身或许更高一级的域名。

document.domain的后话:

应用这类要领是极为轻易的,然则假如一个网站被进击以后别的一个网站极可能会引起平安漏洞。

5.location.hash

这类要领能够把数据的变化显现在 url 的 hash 内里。然则由于 chrome 和 IE 不许可修正parent.location.hash 的值,所以需要再加一层。

a.html 和 b.html 举行数据交换。

a.html

function startRequest(){
    var ifr = document.createElement('iframe');
    ifr.style.display = 'none';
    ifr.src = 'http://2.com/b.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);
b.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,
        // 所以要应用一个中心域下的代办iframe
        var ifrproxy = document.createElement('iframe');
        ifrproxy.style.display = 'none';
        ifrproxy.src = 'http://3.com/c.html#somedata';    // 注重该文件在"a.com"域下
        document.body.appendChild(ifrproxy);
    }
}
c.html

//由于parent.parent和本身属于统一个域,所以能够转变其location.hash的值
parent.parent.location.hash = self.location.hash.substring(1);

如许,应用中心的 c 层就可以够用 hash 到达 a 与 b 的交互了。

6.window.postMessage()

这个要领是 HTML5 的一个新特征,能够用来向其他一切的window对象发送音讯。需要注重的是我们必需要保证一切的剧本实行完才发送MessageEvent,假如在函数实行的过程当中挪用了他,就会让背面的函数超时没法实行。

https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage

参考资料

http://www.cnblogs.com/rainman/archive/2011/02/20/1959325.html

http://www.cnblogs.com/rainman/archive/2011/02/21/1960044.html

硬广

原文地点: https://github.com/rccoder/blog/issues/5

迎接 star 堆栈~

    原文作者:rccoder
    原文地址: https://segmentfault.com/a/1190000004518374
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞