JS系列 - 跨域方法

 

同源策略:

浏览器中有个安全机制,就是同源策略,下面介绍同源策略。同源是指同协议同域名同端口,必须三同,缺一不可。

 

 

限制范围:

(1) Cookie、LocalStorage 和 IndexDB 无法读取。

(2) DOM 无法获得。

(3) AJAX 请求不能发送。

 

避免方案:

1. 设置docnment.domain

两个网页一级域名相同,二级域名不同,浏览器允许通过设置document.domain共享 Cookie。

举例:

A网页是http://w1.example.com/a.html; B网页是http://w2.example.com/b.html

设置相同的document.domain,两个网页就可以共享Cookie。document.domain = 'example.com';

 

iframe上使用:

实现原理:两个页面都通过js强制设置document.domain为基础主域,就实现了同域。

 

2. location.hash的iframe跨域

实现原理:

a 与 b 跨域相互通信,通过中间页c来实现。 三个页面,不同域之间利用iframe的location.hash传值,相同域之间直接js访问来通信。具体步骤:

 

A --> B:

A页面,有个iframe的B页面,A页面通过选择器获取到B的dom节点,在B的src上添加哈希值;

B页面通过监听哈希值的变化,获取到A页面传递的数据;

 

B --> C:

B页面有个iframe的C页面,地址和A页面同源;

B页面通过选择器获取到C的dom节点,在C的src上添加哈希值;

C页面通过监听哈希值的变化,获取到B页面传递的数据;

C页面和A页面同源,所以能获取A页面的window对象(window.parent.parent),通过传参数调用A页面的方法,间接达到B与A通讯;

 

 

3.window.name的iframe跨域

浏览器窗口有window.name属性。这个属性的最大特点是,无论是否同源,只要在同一个窗口里,前一个网页设置了这个属性,后一个网页可以读取它。

  1. 父窗口先打开一个子窗口,载入一个不同源的网页,该网页将信息写入window.name属性。window.name = data;

  2. 接着,子窗口跳回一个与主窗口同域的网址。location = 'http://parent.url.com/xxx.html';

  3. 然后,主窗口就可以读取子窗口的window.name了。var data = document.getElementById('myFrame').contentWindow.name;

这种方法的优点是,window.name容量很大,可以放置非常长的字符串;缺点是必须监听子窗口window.name属性的变化,影响网页性能。

 

4.postMessage跨域(跨文本档、多窗口、跨域消息传递)

HTML5引入了一个全新的API:跨文档通信 API(Cross-document messaging)。这个API为window对象新增了一个window.postMessage方法,允许跨窗口通信,不论这两个窗口是否同源。

 

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

第一个参数是具体的信息内容,

第二个参数是接收消息的窗口的源(origin),即"协议 + 域名 + 端口"。也可以设为*,表示不限制域名,向所有窗口发送。

 

 

父向子发信息:子页面window对象.postMessage(参数, 子页面url)

var popup = window.open('http://bbb.com', 'title');

popup.postMessage('Hello World!', 'http://bbb.com');

 

子向父发信息:父页面window对象.postMessage(参数, 父页面url)

window.opener.postMessage('Nice to see you', 'http://aaa.com');

 

父子窗口通过message事件获取信息

window.addEventListener('message', function(e) {console.log(e.data);},false);

message事件的事件对象event,提供以下三个属性。

    • event.source:发送消息的窗口
    • event.origin: 消息发向的网址
    • event.data: 消息内容

 

下面是iframe通过postMessage进行跨域:

 

5.JSONP

同源政策规定,AJAX请求只能发给同源的网址,否则就报错。除了架设服务器代理,jsonp规避这个限制。

优点:jsonp是服务器与客户端跨源通信的常用方法。简单适用,老式浏览器全部支持,服务器改造非常小。

它的基本思想是,使用<script>标签可以跨域的特点实现,具体步骤如下:

1. 网页动态插入<script>元素,由它向跨源网址发出请求,请求的查询字符串有一个callback参数,指定回调函数的名字。

2. 服务器返回 script 标签的内容,内容就是调用指定的回调函数,并且将返回数据以参数的显示传递;

 

6.CORS

CORS需要浏览器和服务器同时支持。目前所有浏览器都支持该功能,IE浏览器不能低于IE10;

浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)

整个通信过程,都是浏览器自动完成。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。

浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。

 

简单请求:

同时满足以下两大条件,就属于简单请求

1. 请求方法是以下三种方法之一:HEAD、GET、POST

2. HTTP的头信息不超出以下几种字段:Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type:只限于三个值application/x-www-form-urlencodedmultipart/form-datatext/plain

 

基本流程:

1.浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段;Origin字段说明本次请求来自哪个源(协议 + 域名 + 端口)。服务器根据这个值,决定是否同意这次请求。

2.如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现回应的头信息没有包含Access-Control-Allow-Origin字段,抛出一个错误,被XMLHttpRequestonerror回调函数捕获(注意,这种错误无法通过状态码识别,因为HTTP回应的状态码有可能是200)

3.在指定范围,服务器返回的响应,会多出几个头信息字段:

  1. Access-Control-Allow-Origin: http://api.bob.com(请求时Origin字段的值或者*,*表示接受任意域名的请求)

  2. Access-Control-Allow-Credentials: true(布尔值,表示是否允许发送Cookie;默认不发送false; 同时开发者必须在AJAX请求中打开withCredentials属性 xhr.withCredentials = true

  3. Access-Control-Expose-Headers: FooBar (XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。例子指定,getResponseHeader('FooBar')可以返回FooBar字段的值)

 

非简单请求:

对服务器有特殊要求的请求,比如请求方法是PUTDELETE,或者Content-Type字段的类型是application/json;

 

基本流程:

1.会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求;浏览器先询问服务器,当前域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错;("预检"请求用的请求方法是OPTIONS

2.

待续。。。。

参考:http://www.ruanyifeng.com/blog/2016/04/cors.html

 

 

 

 

 

 

posted @ 2017-03-16 11:23  vs1435  阅读(298)  评论(0编辑  收藏  举报