关于跨域

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

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

  • 什么是同源?
    同源就是相同的域名,端口和协议,这三个相同的话就视为同一个域,本域下的JS脚本只能读写本域下的数据资源,无法访问其它域的资源,例如:
    同协议:都是http或者都是https;
    同域名:都是oxc.com;
    同端口:都是8080或者3000;

  • 什么是同源策略?
    同源策略是浏览器为了用户的个人信息以及企业数据的安全而设置的一种策略,不同源的客户端脚本是不能在对方未允许的情况下访问或索取对方的资源;

此图为浏览器因为同源策略报错
  • 同源策略的重要性
    前面所说,同源策略是浏览器为了安全起见而设定,那么如果没有同源策略会发生什么事呢?
    情景一:泄露信息,我登陆了淘宝,然后又登陆了一个恶意网站,恶意网站发送AJAX请求获取淘宝的信息接口,而这个时候我已经登陆过淘宝,所以浏览器附带了我个人的淘宝cookie,一起发送给恶意网站;
    情景二:盗取数据,某网站花重金购买一部电影的播放权,我找到该网站接口后,直接把这部电影拿到手,然后搞到自己的网站上去播放;
    由此可见,为了安全起见的同源策略是必不可少了,但同时也给ajax请求带来了很大的麻烦,比如大型网站不可能把整个网站的所有资源都放在同一个服务器上,这时候跨域就成了必不可少的技能;

  • 什么是跨域?
    跨域就是解决同源策略带来的不便,通过JS去获取不同源之间的数据资源或者进行信息的传递。


跨域的几种实现方法

一、 jsonp

  • 什么是jsonp?

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

  • jsonp的原理和使用步骤

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的使用是需要远端支持的。

  • jsonp的缺陷

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

  • 小实例

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


二、CORS

  • 什么是CROS?

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

  • CORS的兼容性

截图自caniuse网

CORS兼容性

  • 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字段;

  • CORS与jsonp的对比
    • jsonp比CORS优秀的地方
      1.jsonp兼容性较好,而CORS在IE中只兼容IE10以上浏览器,此外在IE7或以下的IE浏览器中,因为没有XMLHttpRequest对象,只支持ActiveX对象,所以注定无法使用CORS,而jsonp这时候就可以大放异彩;
    • CORS比jsonp优秀的地方
      1.CORS在前端部分只需要发送普通的AJAX请求即可,使用起来和不跨域时并无不同,更加的方便;
      2.因为第一条,所以CORS支持其它的请求方式(比如post、put等);
    • 选型
      在有选择的情况下,兼容老浏览器可以使用jsonp,主流浏览器可以选用CORS;

三、降域

  • 什么是降域?

降域就是当两个一级域名相同但二级域名不同时(如: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

  • 什么是postMessage?

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

  • postMessage使用小例子一

需求:当在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>

效果图:

  • postMessage使用小例子二
    1.a.com监听消息事件,并把接收到的消息放进输入框中;
    2.在a.com中用window.open打开b.com,然后在b.com用window.opener.postMessage向a.com的输入框发送消息

步骤图:

第一步:a.com中打开b.com
第二步:在b.com中通过window.opener定位到a.com
第三部:调用b.com的window.opener.postMessage方法向a.com的输入框发送消息
a.com接收到了消息
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容