浏览器同源政策以及JS跨域

浏览器同源政策以及JS跨域

同源是指协定雷同、域名雷同、端口雷同。同源政策的目标,是为了保证用户信息的平安,防备歹意的网站盗取数据。

同源战略重要限定下面三种状况

  • Cookie 没法读取

  • DOM 没法取得

  • AJAX 要求不能发送

同源战略的本意是为了保证用户的信息平安。但偶然也会带来不轻易,下面我们来看一下怎样躲避同源的限定。

Cookie

是效劳器写入浏览器的一小段信息,只需同源的网页才同享。

当两个网页的一级域名雷同,只是二级域名差异的时刻,我们能够经由历程设置document.domain来同享cookie
具体操纵以下:

// 这两个网页的一级域名是雷同的 
http://h1.test.com
http://h2.test.com

//为两个页面设置雷同的 document.domain
document.domain = "test.com"

// 如许两个网页就可以同享`Cookie`

document.domain 不能随便设置,只能把document.domain设置成本身或更高一级的父域。

跨域文档通讯

假如两个网页差异源,就没法拿到对方的DOM,也没法举行通讯。典范的例子是iframe窗口和window.open要领翻开的窗口,它们与父窗口没法通讯。

假如两个窗口一级域名雷同,只是二级域名差异,那末设置上一节引见的document.domain属性,就可以够躲避同源政策,拿到DOM

关于通讯,我们来看一下两种处理方案:

片断辨认符

片断标识符(fragment identifier)指的是,URL#号背面的部份,假如只是转变片断标识符,页面不会从新革新。

//父窗口能够把信息,写入子窗口的片断标识符
var src = originURL + '#' + data;
document.getElementById('myIFrame').src = src;

//子窗口经由历程监听hashchange事宜获得关照
window.onhashchange = checkMessage;

function checkMessage() {
  var message = window.location.hash;
  // ...
}


//一样的,子窗口也能够转变父窗口的片断标识符
parent.location.href= target + "#" + hash;

window.postMessage

window.postMessage 是HTML5为了处理这个题目,引入了一个全新的API,不管两个窗口是不是同源,都允许一个窗口向另一个窗口发送数据。

语法:

// otherWindow 其他窗口的一个援用,比方iframe的contentWindow属性、实行window.open返回的窗口对象

//message 将要发送到其他 window的数据

//targetOrigin 吸收音讯的窗口的源(origin)

otherWindow.postMessage(message, targetOrigin)

其他window能够监听message

//监听 message 事宜

window.addEventListener("message", receiveMessage, false);

//事宜对象有一些常常运用的属性

//data 从其他 window 中通报过来的对象

//origin 音讯发送方窗口的 origin

//source 对发送音讯的窗口对象的援用

function receiveMessage(event){
    var origin = event.origin;
    
    //对发送音讯的源举行考证
    
   if (origin !== "http://example.org:8080")
      return;

  // ...
}

实例:

窗口A : http://xiaoxiong.com
窗口B : http://miaomiao.com
明显这两个窗口差异源,不能通讯,如今我们用postMessage举行通讯。

//Awindow、Bwindow离别示意对 A B 窗口对象的援用
//B窗口向A窗口发音讯
//假如A窗口的协定、主机地点或端口这三者的恣意一项不婚配targetOrigin供应的值,音讯就不能发送胜利
//注重是用 Awindow 挪用 postMessage 要领
 Awindow.postMessage("hello!","http://xiaoxiong.com");
 
 //在A中设置监听事宜
 window.addEventListener("message", receiveMessage, false);
 
 function receiveMessage(event){
    console.log(event.origin);//http://miaomiao.com
    console.log(event.source);// Bwindow
    console.log(event.data);// hello!
    
} 

AJAX

AJAX要求是我们经常常运用到的异步要求要领,然则AJAX要求是不能跨域的。

下面我们看一下罕见的AJAX跨域要领

JSONP

基础思想是,网页经由历程增添一个<script>元素,向效劳器要求JSON数据,这类做法不受同源政策限定;效劳器收到要求后,将数据放在一个指定名字的回调函数里传返来。

function addScript(src) {
  var script = document.createElement('script');
  script.setAttribute("type","text/javascript");
  script.src = src;
  document.body.appendChild(script, body.firstChild);
}

window.onload = function () {
  //要求的查询字符串有一个callback参数,用来指定回调函数的名字,这关于JSONP是必需的
  addScript('http://test.com/a?callback=handler');
}

//要求返来数据作为回调函数的参数
//作为参数的JSON数据被视为JavaScript对象 不必举行转换
function handler(data) {
  console.log(data);
};

JSONP的长处:不受同源战略的限定;它的兼容性更好,在越发陈旧的浏览器中都能够运转;并且在要求终了后能够经由历程挪用callback的体式格局回传效果。

JSONP的瑕玷:它只支撑GET要求而不支撑POST等别的范例的HTTP要求;它只支撑跨域HTTP要求这类状况,不能处理差异域的两个页面之间怎样举行JavaScript挪用的题目。

WebSocket

WebSocket是一种通讯协定,运用ws://(非加密)和wss://(加密)作为协定前缀。该协定不实行同源政策,只需效劳器支撑,就可以够经由历程它举行跨源通讯。

实例:

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com

上面代码中,有一个字段是Origin,示意该要求的要求源(origin),即发自哪一个域名。
恰是由于有了Origin这个字段,所以WebSocket才没有实行同源政策。由于效劳器能够依据这个字段,推断是不是允许本次通讯。假如该域名在白名单内,效劳器就会做出以下回应。

CORS(Cross-origin resource sharing)

跨域资本同享 是官方的跨域处理方案。
全部CORS通讯历程,都是浏览器自动完成,不须要用户介入。关于开发者来讲,CORS通讯与同源的AJAX通讯没有差异,代码完整一样。浏览器一旦发明AJAX要求跨源,就会自动增添一些附加的头信息,偶然还会多出一次附加的要求,但用户不会有觉得。

基础思想
CORS定义了必需在接见跨域资本时,浏览器与效劳器应当怎样沟通。CORS背地的基础思想就是运用自定义的HTTP头部让浏览器与效劳器举行沟通,从而决议要求或相应是应当胜利照样失利。

基础流程

浏览器发明是跨源AJAX要求,浏览器就直接发出CORS要求。具体来讲,就是在头信息当中,增添一个Origin字段。

GET /cors HTTP/1.1
Origin: http://xiaoxiong.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

上面的头信息中,Origin字段用来讲明,本次要求来自哪一个源(协定 + 域名 + 端口)。效劳器依据这个值,决议是不是赞同此次要求。
假如Origin指定的源,不在允许范围内,效劳器会返回一个一般的HTTP回应。浏览器发明,这个回应的头信息没有包括Access-Control-Allow-Origin字段,就晓得出错了,从而抛出一个毛病,被XMLHttpRequestonerror回调函数捕捉。注重,这类毛病没法经由历程状况码辨认,由于HTTP回应的状况码有多是200
假如Origin指定的域名在允许范围内,效劳器返回的相应,会多出几个头信息字段。

Access-Control-Allow-Origin: http://xiaoxiong.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8

Access-Control-Allow-Origin
该字段是必需的。它的值要么是要求时Origin字段的值,要么是一个*,示意接收恣意域名的要求。

CORSJSONP对照,更加先进、轻易和牢靠。

1、 JSONP只能完成GET要求,而CORS支撑一切范例的HTTP要求。

2、 运用CORS,开发者能够运用一般的XMLHttpRequest提议要乞降取得数据,比起JSONP有更好的毛病处理。

3、 JSONP重要被老的浏览器支撑,它们每每不支撑CORS,而绝大多数当代浏览器都已支撑了CORS)。

4、 jsonp在挪用失利的时刻不会返回种种HTTP状况码。

5、在要求终了后能够经由历程挪用callback的体式格局回传效果。将回调要领的权限给了挪用方。这个就相当于将controller层和view层终究分开了。我供应的jsonp效劳只供应纯效劳的数据,至于供应效劳今后的页面衬着和后续view操纵都由挪用者来本身定义就好了。假如有两个页面须要衬着统一份数据,你们只须要有差异的衬着逻辑就可以够了,逻辑都能够运用同 一个jsonp效劳。

参考文献

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