Ajax:Cross-Origin Resource Sharing

来源:互联网 发布:tfidf java高效 编辑:程序博客网 时间:2024/05/10 02:06

       通过XHR实现Ajax通信的一个主要限制,来源于跨域安全策略。默认情况下,XHR对象只能访问与包含它的页面位于同一个域中的资源。这种安全策略可以预防某些恶意行为。但是,实现合理的跨域请求对于开发某些浏览器应用程序也是至关重要的。


       CORS(Cross-Origin Resource Sharing,跨域资源共享)是W3C的一个工作草案,定义了在必须访问跨域资源时,浏览器与服务端应该如何沟通。基本思想是:使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是否成功。


       在发送请求时,需要附加一个额外的Origin头部,其中包含请求页面的源信息(协议、域名和端口),以便服务器根据这个头部信息来决定是否给予响应。如:Origin:http://www.nczonline.net(如果是公共资源,可以返回“*”);


       如果没有这个头部或者是有这个头部但源信息不匹配,浏览器就会驳回请求。注意,请求和响应都不包含cookie信息。


IE浏览器:


       微软在IE8中引入了XDR实现安全可靠地跨域通信,XDR对象的安全机制部分实现了W3C的CORS规范。

       XDR与XHR很相似,不同之处在于:

       1、cookie不会随着请求发送,也不会随响应返回。

       2、只能设置请求头部信息中的Content-Type字段。

       3、不能访问响应头部信息。

       4、只能支持GET和POST请求。


       被请求的资源可以根据它认为合适的任意数据(用户代理、来源页面等)来决定是否设置Access-Control-Allow-Origin头部。作为请求的一部分,Origin头部的值表示请求的来源域,以便远程资源明确地识别XDR请求。


       XDR对象的open()方法只接收两个参数:请求的类型和URL。所有的XDR请求都是异步执行的,不能用它来创建同步请求。请求返回之后,会触发load事件,响应的数据也会保存在responseText属性中。


       在接收到响应后,只能访问响应的原始文本,没有办法确定响应的状态代码。而且,只有响应有效就会触发load事件。如果失败(包括响应中缺少Access-Control-Allow-Origin头部)就会触发error事件。除了错误本身之外,没有其他信息可用,因此唯一能够确定的就只有请求未成功了。鉴于导致XDR请求失败的因素很多,可以通过onerror事件处理程序来捕获该事件,否则,即使请求失败也不会有任何提示。


Firefox 3.5+、Safari 4+、Chrome:


       这些浏览器请求位于领一个域中的资源,使用标准的XHR对象并在open()方法中传入绝对URL即可。

       与IE中的XDR对象不同,通过跨域XHR对象可以访问status和statusText属性,而且还支持同步请求。跨域XHR对象也有一些限制,但是为了安全这些限制是必须的。

       1、不能使用setRequestHeader()设置自定义头部。

       2、不能发送和接收cookie。

       3、调用getAllResponseHeaders()方法总会返回空字符串。


       由于无论同源请求还是跨源请求都是用相同的接口。因此对于本地资源,最好使用相对URL,在访问远程资源时再使用绝对URL。这样做能消除歧义,避免出现限制访问头部或本地cookie信息等问题。


Preflighted Requests:


       CORS通过一种叫做Preflighted Requests的透明服务器验证机制支持开发人员使用自己的头部、GET或POST之外的方法,以及不同类型的主题内容。发送Preflighted Requests使用OPTIONS方法,发送下列头部:

       1、Origin:与简单的请求相同。

       2、Access-Control-Request-Method:请求自身使用的方法。

       3、Access-Control-Request-Headers:(可选)自定义的头部信息,多个头部以逗号隔开。

       服务器可以决定是否允许这种类型的请求。服务器通过在响应中发送如下头部与浏览器进行沟通。

       1、Access-Control-Allow-Origin:与简单的请求相同。

       2、Access-Control-Allow-Method:允许的方法,多个方法以逗号隔开。

       3、Access-Control-Allow-Headers:允许的头部,多个头部以逗号隔开。

       4、Access-Control-Max-Age:应该将这个Preflighted Requests缓存多长时间(以秒表示)

       Preflighted 请求结束后,结果将按照响应中指定的时间缓存起来。而为此付出的代价只是第一次发这种请求时会多一次HTTP请求。


带凭据的请求:


       默认情况下跨源请求提供凭据(cookie、HTTP认证以及客户端SSL证明等)。通过withCredentials属性设置为true,可以指定某个请求应该发送凭据。如果服务器接受带凭据的请求,会用下面的HTTP头部来响应。

       Access-Control-Allow-Credentials:true。

       如果发送的是带凭据的请求,但服务器的响应中没有包含这个头部,那么浏览器就不会把响应交给Javascript(于是,responseText将是空字符串,status的值是0,而且会调用onerror()事件处理程序)。服务器也可以在Preflight响应中发送这个HTTP头部,表示允许源发送带凭据的请求。


CORS的兼容性:

       即使浏览器对CORS的支持程度不一样,但是所有浏览器都支持简单的(非Preflight和不带凭据的)请求。检测是否存在withCredentials属性,就可以知道XHR是否支持CORS,再结合检测XDomainRequest对象是否存在,就可以兼顾所有的浏览器。

funtion createCORSRequest(method,url){var xhr = new XMLHttpRequest();if("withCredentials" in xhr){xhr.open(method,url,true);}else if(typeof XDomainRequest != "undefined"){xhr = newXDomainRequest();xhr.open(method,url);}else{xhr = null;}return xhr;}var request = createCORSRequest("get",url)if(request){request.onload = function(){//对request.responseText进行处理};request.send();}


原创粉丝点击