常见的跨域解决方案

1、JSONP

受浏览器同源策略的限制,网页无法向其他域发送ajax请求,但在页面中引入其他域的脚本是可以的,最常见的例子就是在页面中引入cdn服务器上的js文件及图片等静态资源,JSONP正是利用这一特性实现了跨域。
例如,http://test.com/test.html获取http://abc.test.com/data.php上的数据,那么只需要在test.html中加入以下代码即可:

<script>
    function handleData(data){
        // do something
    }
</script>
<script scr="http://abc.test.com/data.php?callback=handleData"></script>

其实第二个标签返回的是一个可执行的js文件,data.php包含这样一段代码:

<?php
$callback = $_GET['callback']; 
$data = array(1,2);
echo $callback.'('.json_encode($data)')'
?>

当第二个标签加载完毕后,就会执行handleData([1,2])

2、document.domain

浏览器同源策略中第二个限制是不同域的框架之间不能进行js交互(但可获得彼此的window对象)
例如,在http://abc.test.com/test.html这个页面中有一个iframe起src为http://bcd.test.com/test2.html,以下代码会出现注释中的问题

//test.html
<script>
    function ifrLoad(){
        var iframe=document.getElementById('iframe');
        var ifrWin=iframe.contentWindow; //获得iframe的window对象(但属性和方法几乎不可用)
        console.log(ifrWin.document); //无法获得document属性
    }
</script>
<iframe src="http://bcd.test.com/test2.html" id="iframe" onload="ifrLoad()" ></iframe>

此时可通过document.domain设置当前文档的原始域实现跨域操作,只要两个页面的原始域相同,就可通过js获得iframe中的各种属性和方法了.

<!-- test.html   -->
<script>
   document.domain='test.com'
   function ifrLoad(){
       var iframe=document.getElementById('iframe');
       var ifrWin=iframe.contentWindow; //获得iframe的window对象(但属性和方法几乎不可用)
       console.log(ifrWin.document);  //正常
   }
</script>
<iframe src="https:www.baidu.com" id="iframe" onload="ifrLoad()" ></iframe>
<!-- test2.html -->
<script>
    document.domain='test.com'
</script>

需要要注意的是,d只能把document.domain设置成自身或更高一级的父域,且主域必须相同。例如:a.b.test.com 中某个文档的document.domain 可以设成a.b.test.com、b.test.com 、test.com中的任意一个,但是不可以设成 c.a.b.test.com,因为这是当前域的子域,也不可以设成example.com,因为主域已经不相同了。

3 、window.name

window.name属性在不同的页面(甚至不同域名)加载后依旧存在(如果没修改则值不会变化),并且可以支持非常长的 name 值(2MB)假设我们在百度首页设置了window.name为'baidu',

我们在同一窗口地址栏中输入谷歌网址,此时我们查看window.name会发现window.name依然为‘baidu’

此时我们修改window.name为'google',再次打开百度,发现window.name变为了‘google’


了解了window.name属性之后,我们想要从test页面中获得test1中的数据就容易多了,可以首先加载test1页面,将test页面需要的数据存在window.name中,然后加载test页面,但貌似这种方式很蠢,解决办法是在test页面中设置一个隐藏的iframe标签用于获取test2页面的window.name,但需要注意的是受同源策略的限制,需要在iframe中的test2加载完毕后,在iframe中加载与test同源的test3页面。

<!-- http://abc.test.com/test.html   -->
<script>
    function loadData(){
        var iframe=document.getElementById('iframe');
        iframe.onload=fucntion(){
            var data=iframe.contentWindow.name
            console.log(data)
        }
        iframe.src='http://abc.test.com/test3.html'

    }
</script>
<iframe src="http://bcd.test.com/test2.html" id="iframe" onload="loadData()" ></iframe>

4、window.postMessage

window.postMessage是HTML5的API,允许跨域在两个窗口/frames之间发送数据。需要注意的是调用postMessage方法的window对象是指接受消息的那个window对象。其调用方式如下:

otherWindow.postMessage(message, targetOrigin, [transfer]);

otherWindow 是其他窗口的一个引用,比如iframe的contentWindow属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames。
argetOrigin 是用来接收消息的那个window对象所在的域,如果不希望做限定,可以用*代替。
transfer 可选,是一串和message 同时传递的 Transferable 对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。

<!-- http://abc.test.com/test.html   -->
<script>
    function ifrLoad(){
        var iframe=document.geElementById('iframe');
        iframe.contentWindow.postMessage('hello world!','*')
    }
</script>
<iframe src="http://bcd.test.com/test2.html" id="iframe" onload="ifrLoad()" '></iframe>
<!-- test2.html -->
<script>
    window.onmessage=function(e){
        console.log(e.data)
    }
</script>

5 、跨域资源共享(CORS)

服务器设置Access-Control-Allow-OriginHTTP响应头之后,浏览器将会允许跨域请求,但需要浏览器需要支持HTML5,可以支持POST,PUT等方法

HTML5标准中提出的跨域资源共享(Cross Origin Resource Share,CORS)支持其他的HTTP方法如PUT, POST等,可以从本质上解决跨域问题。
例如,从http://a.com要访问http://b.com的数据,通常情况下Chrome会因跨域请求而报错:

XMLHttpRequest cannot load http://b.com. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://a.com' is therefore not allowed access.

错误原因是被请求资源没有设置Access-Control-Allow-Origin,所以我们在b.com的服务器中设置这个响应头字段即可:

Access-Control-Allow-Origin: * # 允许所有域名访问,或者
Access-Control-Allow-Origin: http://a.com # 只允许所有域名访问

为 xhr设置 withCredentials后CORS方法跨域还可携带Cookie,但 PUT/POST 请求需要注意处理 preflight 请求

6、Proxy

可以在服务器端设置一个代理,由服务器端向跨域下的网站发出请求,再将请求结果返回给前端,成功避免同源策略的限制。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 什么是同源策略 同源策略是指浏览器处于安全方面的考虑只允许本域下的接口交互。不同源的客户端脚本在没有明确授权的情况...
    夜流光丶阅读 281评论 0 0
  • 什么是跨域? 2.) 资源嵌入:、、、等dom标签,还有样式中background:url()、@font-fac...
    电影里的梦i阅读 2,393评论 0 5
  • 1. 什么是跨域? 跨域一词从字面意思看,就是跨域名嘛,但实际上跨域的范围绝对不止那么狭隘。具体概念如下:只要协议...
    w_zhuan阅读 541评论 0 0
  • 1. 什么是跨域? 跨域一词从字面意思看,就是跨域名嘛,但实际上跨域的范围绝对不止那么狭隘。具体概念如下:只要协议...
    他在发呆阅读 830评论 0 0
  • 打嗝其实是人类进化的产物,也是身体的保护反应。 在胸腔和腹腔之间,有一个肌肉膜叫膈肌,厚厚的、像帽子,把胸腔和腹腔...
    美妙的养生阅读 346评论 0 0