zoukankan      html  css  js  c++  java
  • 浅谈跨域

    引言

      使用XHR对象进行Ajax通讯的主要限制,就是跨域的资源访问。默认情况下,XHR只能访问与包含它的页面位于同一个域中的资源。这种安全策略可以预防某些恶意的行为。但是,实现合理的跨与请求对于开发某些应用程序也是必要的。下面,我们就来介绍下关于跨域这方面的知识。

     CORS简介

      CORS(跨域资源共享)是W3C定义的一个工作草案,定义了在必须进行跨域资源访问时,浏览器与服务器之间的通讯。CORS背后的思想是这样的:使用自定义的Http头部让浏览器和服务器进行通讯,从而决定响应是成功的还是失败的。

      例如我们使用GET或者POST发送一个请求时,它默认是没有自定义头部的。在发送该请求时,需要额外添加一个Origin头部(包含请求页面的源信息:协议、域名和端口),以便服务器根据这个头部来决定是否给予响应。

      例如:我们需要跨域访问http://www.nczonline.net。那么浏览器会将Origin设置为这个URL地址。如果服务器认为这个请求可以接受,就在Access-Control-Allow-Origin中回发相同的源信息。如果没有这个头部,或者这个头部源信息不匹配,浏览器就会拒绝进行跨域的请求。

      下面介绍一个完整的例子,如下:

      假设我们页面或者应用已在 http://www.test1.com 上了而我们打算从 http://www.test2.com 请求提取数据。一般情况下,如果我们直接使用 AJAX 来请求将会失败,浏览器也会返回“源不匹配”的错误,这就是跨域。

      利用 CORS,http://www.test2.com 只需添加一个标头,就可以允许来自 http://www.test1.com 的请求,下图是我在PHP中的 hander() 设置,“*”号表示允许任何域向我们的服务端提交请求
         

    IE对CORS的实现

      IE8中引入了XDR(XDomainRequest)对象来支持跨域的请求。这个对象与XHR对象类似,但它可以实现安全可靠的跨域访问。但是XDR对象和XHR对象相比还是有一些不同的。主要在以下几点。

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

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

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

      4、只支持GET和POST请求。

      注意:XDR对象open方法只有两个参数。请求的类型和URL.所有的XDR都是异步进行的。请求返回后,会触发onload事件,响应的数据保存在responseText中。例子如下:

    1 domainRequest = new XDomainRequest();
    2 domainRequest.open(method, url);
     this.domainRequest.send(null);
    3 //注册相关回调函数 4 this.domainRequest.onload = callback; 5 this.domainRequest.onerror = failback;

      注意:由于导致XDR失败的因素很多,建议使用onerror事件来处理异常。

    其他浏览器对CORS的支持

      Firefox 3.5+、Safiri 4+、Chrome、iOS系统的Safiri以及Android平台的WebKit都XMLHttpRequest对象实现了CORS的原生支持。在尝试打开不同来源的资源时,无需额外编写代码户可以触发这个行为。要请求位于另一个域中的资源,使用标准的XHR对象并在open中传入绝对路径即可。(http://.....)。

      与IE中的XDR对象不同,通过跨域XHR对象可以访问status和statusText属性,而且还支持同步请求。跨域XHR对象也存在一些限制。如:

      不能使用setRequestHander()设置自定义头部

      不能发送和接收cookie

      调用getAllResponseHeaders()总会返回空字符串

    跨浏览器的CORS

      各种浏览器对CORS的支持程度都不一样。但所有浏览器都支持简单的请求。下面通过代码来介绍下跨浏览器的CORS实现。如下:

     1 /**
     2  * 跨域版本的Ajax.在IE8-IE10中是使用XDomainRequest来实现CORS.注意:IE11不支持XDomainRequest
     3  * 其他主流浏览器可以使用XMLHttpRequest来实现跨域
     4  * method:调用ajax的方式:get/post
     5  * url:调用服务端方法的路径(asmx,controller都可).如:Login/CheckUser注意get,post时不要使用?Id=XX&Name=XX等形式
     6  **/
     7 function DomainAjaxInstance(method, url) {
     8     var domainRequest = new XMLHttpRequest();
     9     if ("withCredentials" in domainRequest) {
    10         // 此时即支持CORS的情况
    11         // 检查XMLHttpRequest对象是否有"withCredentials"属性
    12         // "withCredentials"仅存在于XMLHTTPRequest2对象里
    13         domainRequest.open(method, url, true);
    14     }
    15     //IE8,9中跨域访问对象XDR
    16     else if (typeof XDomainRequest != "undefined") {
    17         domainRequest = new XDomainRequest();
    18         domainRequest.open(method, url);
    19     }
    20     else {
    21         domainRequest = null;
    22     }
    23     //保存调用的相关参数
    24     this.domainRequest = domainRequest;
    25     this.method = method;
    26     this.url = url;
    27 }
    28 
    29 /**
    30  * 跨域访问(跨域访问支持仅GET和POST)
    31  * data:调用方法时传递的参数.只需要以对象形式{Id:"",Name:""}传递data参数即可,无参传递null
    32  * callback:获取结果的回调函数
    33  * failback:跨域调用出错时的回调函数
    34  **/
    35 DomainAjaxInstance.prototype.call = function (data, callback, failback) {
    36     if (!(callback instanceof Function) || !(failback instanceof Function)) {
    37         alert("调用call方法必须指定callback和failback方法");
    38         return;
    39     }
    40     var query = null;
    41     if (data !== null && (data instanceof Object)) {
    42         query = appendParameters(data);
    43     }
    44     var type = this.method;
    45     if (type.toLowerCase() == "post") {
    46         this.domainRequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    47         this.domainRequest.send(query);
    48     }
    49     else {
    50         var url = this.url;
    51         if (query !== null) {
    52             url += (url.indexOf("?") == -1) ? "?" : "&";
    53             url += query;
    54         }
    55         this.domainRequest.send(null);
    56     }
    57     //注册相关回调函数
    58     this.domainRequest.onload = callback;
    59     this.domainRequest.onerror = failback;
    60 }

    其他跨域技术

      JSONP

      JSONP是填充式JSON或者参数式JSON的缩写,是一种应用JSON的新方法。JSONP看起来和JSON差不多,只是被包含在函数调用中的JSON。一般调用方式是这样:callback({"name":"Nicolas"})。

      JSONP由两部分组成,回调函数和数据。回调函数是当响应到来的时应该在页面调用的函数。回调函数的名称一般都是在页面中指定的。数据就是传入回调函数的JSON数据。

    下面展示一个典型的JSONP请求:

      http://freegeiop.net/json/?callback=handlerRsoponse(回调函数名称是:handlerRsoponse)。

      JSONP是通过动态<script>标签来使用的。使用时通过为<script>标签设定src属性是一个跨域的URL。这里的<script>标签与<img>标签类似,都有能力不限制的从其他域加载资源。

      当然JSONP也存在不足,主要表现在下面两点

      1、JSONP是从其他域加载代码执行的,如果其他域不安全,很可能会在响应中夹杂着恶意代码。所以使用JSONP时一定要确保安全可靠。

      2、要确定JSONP请求是否失败并不容易,现阶段开发人员只能使用定时器来检测是否接收到响应。

    相关资料

      对于JSONP,下面两篇博文介绍的不错,推荐给大家。大家可以看看JQuery中怎么使用这种跨域技术的。

      http://kb.cnblogs.com/page/139725/

      http://justcoding.iteye.com/blog/1366102

  • 相关阅读:
    POJ 3672 水题......
    POJ 3279 枚举?
    STL
    241. Different Ways to Add Parentheses
    282. Expression Add Operators
    169. Majority Element
    Weekly Contest 121
    927. Three Equal Parts
    910. Smallest Range II
    921. Minimum Add to Make Parentheses Valid
  • 原文地址:https://www.cnblogs.com/dreamGong/p/4959401.html
Copyright © 2011-2022 走看看