技术知识饥人谷技术博客JS

关于跨域

2017-02-10  本文已影响265人  大春春

前段时间学习了AJAX,已经可以从后台拿到JSON串。可是出现了问题,目前我发送的请求都是在同域下的请求,如果我想拿到其它域的数据,便会受到浏览器的同源策略限制,于是便学习的跨域的相关知识,这篇文章便是用于对这些知识进行复习。

一、关于浏览器的同源策略和跨域

此图为浏览器因为同源策略报错

跨域的几种实现方法

一、 jsonp

JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。

jsonp其实就是利用script标签本身可跨域,并且可以将其src属性里的资源下载下来的设定从而达成目的。
具体使用步骤如下:
本域部分:
1.首先动态创建script标签;
2.创建回调函数callback(假定函数名为aaa),然后将该函数与callback字段结合成键值对的形式,例如:callback=aaa,接着将其与远端(不同源)的接口url结合成如下形式:
http.....................php?callback=aaa
3.将创建的script标签的src引向结合后的接口http.....................php?callback=aaa即可;
跨域服务器部分:
1.获取到回调函数aaa后,把需要发送的数据与函数aaa进行包装,使用字符串拼接的方式组成如下形式再发回给本域:
aaa({"name": "xiaoming", "age": "1000"});
这时候数据就已经到手了
最后:
浏览器会调用函数aaa,把获得的数据以参数形式传递进去,进行数据处理;
PS:由上述步骤可见,jsonp的使用是需要远端支持的。

1.因为src属性自己获取数据要在url后面加上数据参数,那么这个方式就只有get,所以jsonp也只能用get方式获取数据;
2.jsonp只能解决跨域获取资源问题,但是不能解决不同域页面之间的JS调用问题;
3.安全性问题:如果提供jsonp的远端存在注入漏洞,它返回的数据就有可能是被人操控的。那么调用过这个远端接口的所有网页就都有可能被操控;
4.jsonp调用失败不会返回失败的http状态码,有可能会是200OK;

一个运用了jsonp制作出来的半成品音乐播放器


二、CORS

CROS全称Cross-Origin Resource Sharing(跨域资源共享),它是一个W3C标准,支持使用AJAX向跨域服务器发出AJAX请求;

截图自caniuse网

CORS兼容性

个人类比:同源策略好比一个黑名单,这个黑名单非常严格,把所有的不同源客户端脚本都进行了限制访问,而CORS则是一个白名单,可以将允许访问的客户端脚本添加进这个白名单中,使其能进行访问;

CORS通信的实现只能依赖跨域服务器的支持,而在本域下的的代码只是普通的AJAX请求;
通过在跨域服务器中对回应头进行设置,实现对指定的域进行数据交互,如下代码是对回应头进行的设置
header("Access-Control-Allow-Origin", "a.oxc.com")
这个代码实现了a.oxc.com这个域名对其数据的访问;

1.本域:发出普通的AJAX请求
2.跨域服务器:添加回应头信息:header('Access-Control-Allow-Origin', '允许跨域进行访问的域名')
PS:这个回应头信息中Access-Control-Allow-Origin是允许跨域访问,而后面的域名是允许进行跨域访问的域名,如果第二个参数是一个星号*,就是无限制,所有的域都可以对其进行跨域访问;
3.本域分两种情况:
已经被允许跨域访问:
在回应头处出现一个键值对,如:Access-Control-Allow-Origin: http://a.com:8080
未允许进行跨域访问:
①:可能是跨域服务器不支持CORS跨域访问,那么就不会有类似:Access-Control-Allow-Origin: http://a.com:8080的回应头信息;
②:跨域服务器不支持本域进行访问,也会有回应头信息,该信息标注那些域是可以进行访问的,比如:跨域服务器支持a.com进行访问,而我用b.com对其进行访问,回应头就会回复:Access-Control-Allow-Origin: http://a.com:8080字段,表明只有a.com是支持访问的;
出现如下错误:

需求:用a.oxc.com获取接口为b.oxc.com的服务器上发回的信息

1.修改hosts文件:

修改hosts文件

2.写一个按钮,点击获取数据,接口号为:'http://b.oxc.com:8080/hello'

  <button id="btn">点击</button>
  <script>
    var btn = document.querySelector('#btn');
    btn.addEventListener('click', function(){
      var xhr = new XMLHttpRequest();
      xhr.onreadystatechange = function(){
        if(xhr.readyState === 4){
          if(xhr.status === 200){
            console.log(xhr.responseText)
          }
        }
      }
      xhr.open('get', 'http://b.oxc.com:8080/hello', true)
      xhr.send();
    })

3.跨域服务器设置回应头,只允许a.oxc.com对其进行访问:
header('Access-Control-Allow-Origin', 'http://a.oxc.com:8080')

4.效果图:

打印回应信息 回应头 用其他域名对其进行访问的回应头信息

此外,我们还可以对回应头的一些信息进行设置:
1.Access-Control-Allow-Credentials
该信息指定是否发送cookie,可以设置true或者false,true是允许,false为不允许;
2.Access-Control-Expose-Headers
因为XMLHttpRequest对象中的getResponseHeader()方法只能接受6个基本的回应头信息:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma,如果需要拿到更多的回应头信息就要对Access-Control-Expose-Headers进行设置,例如:
Access-Control-Expose-Headers: aaa就能拿到回应头信息中的aaa字段;


三、降域

降域就是当两个一级域名相同但二级域名不同时(如:a.oxc.com和b.oxc.com中主域名都是oxc.com),对两个域名都设置document.domain = 主域名来达到跨域的目的;

使用降域来达成跨域的目的有非常大的限制性:
1.主域名要相同:a.com和b.com就不行,a.oxc.com和b.oxc.com就可以;
2.降域只适用于iframe窗口和获取cookie,但不能获取LocalStorage 和 IndexDB ;

需求:当在a.oxc.com的输入框中输入字符,b.oxc.com的输入框中也会出现相同字符

1.写下a页面(a.oxc.com)和b(b.oxc.com)页面,其中b页面通过a页面的iframe标签嵌入了a页面
a页面:

<body>
<div>
    <input type="text" id="ipt" placeholder="a.oxc">
</div>
<iframe src="http://b.oxc.com:8080/b.html" frameborder="0" scrolling="no"></iframe>
    <script>
        // 获取输入框
       var ipt = document.querySelector('#ipt');
       ipt.addEventListener('input', function(e) {
        // 获取b的输入框输入的字段,让a的输入框字段相等
         window.frames[0].ipt.value = this.value
         console.log(this.value);
       })


    </script>
</body>

b页面:

<body>
<div>
    <input type="text" id="ipt" placeholder="b.oxc">
</div>

    <script>
       var ipt = document.querySelector('#ipt');
       ipt.addEventListener('input', function(e) {
        // 让a的输入框的字段与b的输入框的字段相等
         window.parent.frames.ipt.value = this.value;
       })
       

    </script>
</body>

2.为a和b页面分别添加document.domain = oxc.com

3.效果图:


降域小例子效果图

4.a页面的cookie,b页面也可以进行读取



四、postMessage

1.postMessage是window对象下的一个方法,他使得不同主域名之间也可以进行跨域通信:例如:使用a.com向b.com进行通信;
2.postMessage方法接收两个参数,第一个参数是需要发送的消息,第二个参数接收发送的域名,如:
window.postMessage('abc', 'a.com')

需求:当在a.com的输入框中输入字符,b.com的输入框中也会出现相同字符;
代码如下:

a.com代码:

<div>
    <input type="text" id="ipt" placeholder="a.oxc">
</div>
<iframe src="http://b.com:8080/b.html" frameborder="0" scrolling="no"></iframe>
    <script>
       var ipt = document.querySelector('#ipt');
       ipt.addEventListener('input', function(e) {
         window.frames[0].postMessage(this.value, 'http://b.com:8080')
         console.log(this.value);
       })

       // 监听message事件
       window.addEventListener('message', function(e){
          ipt.value = e.data;
       })

b.com代码:

<div>
    <input type="text" id="ipt" placeholder="b.oxc">
</div>

    <script>
       var ipt = document.querySelector('#ipt');
       ipt.addEventListener('input', function(e) {
         window.parent.frames.postMessage(this.value, 'http://a.com:8080')
       })
       
       window.addEventListener('message', function(e){
          ipt.value = e.data;
       })
    </script>

效果图:

步骤图:

第一步:a.com中打开b.com 第二步:在b.com中通过window.opener定位到a.com 第三部:调用b.com的window.opener.postMessage方法向a.com的输入框发送消息 a.com接收到了消息
上一篇下一篇

猜你喜欢

热点阅读