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

  • 相关阅读:
    正则表达式尽量写的精简,提高运行效率
    IndexError:string index out of range
    Python3 字符编码
    python3字符编码错误
    pip
    正则贪婪和非贪婪
    [Ss]+ 可以匹配多行html,最常用的还是.*?
    正则,分组,字符集,使用场景
    使用jodis连接codis的时候报异常:Exception in thread "main" redis.clients.jedis.exceptions.JedisException: Proxy list empty
    codis 的dashboard服务无法启动 提示pid已经运行
  • 原文地址:https://www.cnblogs.com/dreamGong/p/4959401.html
Copyright © 2011-2022 走看看