ajax跨域访问 JQuery的跨域详解

JS的跨域问题,我想很多程序员的脑海里面还认为JS是不能跨域的,其实这是一个错误的观点;

有很多人在网上找其解决方法,教其用IFRAME去解决的文章很多,真有那么复杂吗?

其实很简单的,如果你用JQUERY,一个GETJSON方法就搞定了,而且是一行代码搞定。

今天2013年8月2日又抽时间整理了下,修改了优化在线调用的方法。

我这里提供了在线测试调用的功能,方便大家测试。点击查看

其实跨域有两种思路,思路一:就是通过js跨域访问;思路二:是通过后台写代码访问

下面说下两种方法的实现:

思路一:通过js跨域访问

一、服务器端(远程访问段),构造指定的json格式:

 代码如下 复制代码
var url = "http://www.111cn.net  /CsAjax.do?method=getCrossJson&jsoncallback=?"
$.getJSON(url,
    {www_url:"www.111cn.net"},
    function(json) { 
      //返回格式: ?(json_data) 
      /*返回数据: ?([{"www_url":"www.111cn.net","www_name":"www_name",
            "items":[{"p_name":"安徽省","p_index":340000},{"p_name":"北京市","p_index":110000}]}]) */
      //调用实例:alert(json[0].www_url); 
    }); 
 

注意:CsAjax.do?method=getCrossJson中,在输出JSON数据时,一定要带参数:jsoncallback,并将获取的内容放到返回JSON数据的前面,假设实际获取的值为Jquery123456_7890123,那么返回的值就是 Jquery123456_7890123([{"www_url":"www.111cn.net","www_name":"www_name","items":[{"p_name":"安徽省","p_index":340000},{"p_name":"北京市","p_index":110000}]}]);

这个贴上我的远程端的获取代码java写的其他语言类似参考:

   

 代码如下 复制代码
     String www_url = (String) request.getAttribute("www_url");
String jsoncallback = (String) request.getAttribute("jsoncallback");
if (StringUtils.isBlank(www_url)) {
    www_url = "www.111cn.net";
}
JSONObject jsonb = new JSONObject();
 
jsonb.put("www_url", www_url);
jsonb.put("www_name", "爱森家园");
 
JSONArray items = new JSONArray();
JSONObject item = new JSONObject();
item.put("p_name", "安徽省");
item.put("p_index", 340000);
items.put(item);
jsonb.put("p_name", "北京市");
jsonb.put("p_index", 110000);
items.put(item);
jsonb.put("items", items);
 
String json = jsoncallback + "([" + jsonb.toString() + "])";
if (StringUtils.isNotBlank(jsoncallback)) {
    //将特殊构造的数据:json 返回到页面
} else {
    //将正常的数据jsonb返回到页面
}

因为getJSON跨域的原理是把?随机变一个方法名,然后返回执行的,实现跨域响应的目的。

二、客户端实际调用, 下面一个是跨域执行的真实例子(可跨所有域名):

 代码如下 复制代码

<script src="/scripts/jquery.js" type="text/javascript"></script>
<script type="text/javascript">
$.getJSON("http://www.111cn.net  /CsAjax.do?method=getCrossJson&jsoncallback=?",
{www_url:"www.111cn.net"},
function(json) {
alert(json[0].www_url);
alert(json[0].www_name);
alert(json[0].items[0].p_name);
});
</script>

后台写代码访问

第一种思路有一个缺陷:就是如果需要访问的服务端你无法控制的话,那么你也就无计可施了,所以提供第二种思路,后台通过HttpClient 和 HttpGet 直接访问,

然后在后台获取访问的数据,在做处理,返回到页面即可。

这个可以参考我的文章:有道翻译 使用

jQuery跨域原理

浏览器会进行同源检查,这导致了跨域问题,然而这个跨域检查还有一个例外那就是HTML的<Script>标记;我们经常使用<Script>的src属性,脚本静态资源放在独立域名下或者来自其它站点的时候这里是一个url;这个url 响应的结果可以有很多种 , 比如 JSON, 返回的 Json 值成为 <Script> 标签的 src 属性值 . 这种属性值变化并不会引起页面的影响 . 按照惯例,浏览器在 URL 的查询字符串中提供一个参数,这个参数将作为结果的前缀一起返回到浏览器 ;

看下面的例子:

 代码如下 复制代码
<script type="text/javascript" src="http://domain2.com/getjson?jsonp=parseResponse"> </script>

响应值:parseResponse({"Name": "Cheeso", "Rank": 7})

这种方式被称作 JsonP ;(如果链接已经失效请点击这里: JSONP ) ;即:JSON with padding 上面提到的前缀就是所谓的“padding”。 那么 jQuery 里面是怎么实现的呢?

貌似并没有 <Script> 标记的出现!? OKay ,

页面调用的是getJSON:

 代码如下 复制代码
getJSON: function ( url, data, callback ) {
        return jQuery.get(url, data, callback, " json " );
    },

 
继续跟进

 代码如下 复制代码
get: function ( url, data, callback, type ) {
     // shift arguments if data argument was omited 
       if ( jQuery.isFunction( data ) ) {
         type = type || callback;
         callback = data;
          data = null ;
     }
 
     return jQuery.ajax({
         type: " GET " ,
         url: url,
         data: data,
         success: callback,
         dataType: type
     });
 
  

跟进 jQuery.ajax,下面是 ajax 方法的代码片段:

 代码如下 复制代码
// Build temporary JSONP function 
       if ( s.dataType === " json " && (s.data && jsre.test(s.data) || jsre.test(s.url)) ) {
         jsonp = s.jsonpCallback || ( " jsonp " + jsc ++ );
  
         // Replace the =? sequence both in the query string and the data 
           if ( s.data ) {
             s.data = (s.data + "" ).replace(jsre, " = " + jsonp + " $1 " );
         }
  
        s.url = s.url.replace(jsre, " = " + jsonp + " $1 " );
 
        // We need to make sure 
          // that a JSONP style response is executed properly 
          s.dataType = " script " ;
 
        // Handle JSONP-style loading 
          window[ jsonp ] = window[ jsonp ] || function ( tmp ) {
            data = tmp;
            success();
            complete();
            // Garbage collect 
              window[ jsonp ] = undefined;
 
            try {
                delete window[ jsonp ];
            } catch (e) {}
 
            if ( head ) {
                head.removeChild( script );
            }
        };
    }
 
    if ( s.dataType === " script " && s.cache === null ) {
        s.cache = false ;
    }
 
    if ( s.cache === false && type === " GET " ) {
        var ts = now();
 
        // try replacing _= if it is there 
          var ret = s.url.replace(rts, " $1_= " + ts + " $2 " );
 
        // if nothing was replaced, add timestamp to the end 
          s.url = ret + ((ret === s.url) ? (rquery.test(s.url) ? " & " : " ? " ) + " _= " + ts : "" );
    }
 
    // If data is available, append data to url for get requests 
      if ( s.data && type === " GET " ) {
        s.url += (rquery.test(s.url) ? " & " : " ? " ) + s.data;
    }
 
    // Watch for a new set of requests 
      if ( s.global && ! jQuery.active ++ ) {
        jQuery.event.trigger( " ajaxStart " );
    }
 
    // Matches an absolute URL, and saves the domain 
      var parts = rurl.exec( s.url ),
        remote = parts && (parts[ 1 ] && parts[ 1 ] !== location.protocol || parts[ 2 ] !==location.host);
 
    // If we're requesting a remote document 
      // and trying to load JSON or Script with a GET 
      if ( s.dataType === " script " && type === " GET " && remote ) {
        var head = document.getElementsByTagName( " head " )[ 0 ] || document.documentElement;
        var script = document.createElement( " script " );
        script.src = s.url;
        if ( s.scriptCharset ) {
            script.charset = s.scriptCharset;
        }
 
        // Handle Script loading 
          if ( ! jsonp ) {
            var done = false ;
 
            // Attach handlers for all browsers 
              script.onload = script.onreadystatechange = function () {
                if ( ! done && ( ! this .readyState || 
                        this .readyState === " loaded " || this .readyState === " complete " ) ) {
                    done = true ;
                    success();
                    complete();
 
                    // Handle memory leak in IE 
                      script.onload = script.onreadystatechange = null ;
                    if ( head && script.parentNode ) {
                        head.removeChild( script );
                    }
                }
            };
        }
 
        // Use insertBefore instead of appendChild  to circumvent an IE6 bug. 
          // This arises when a base node is used (#2709 and #4378). 
          head.insertBefore( script, head.firstChild );
 
        // We handle everything using the script element injection 
          return undefined;
    }

上面的代码第1行到第10行:判断是JSON类型调用,为本次调用创建临时的JsonP方法,并且添加了一个随机数字,这个数字源于用日期值;

这个地方也就是Taven.李锡远所说的“随机变一个方法名”;

关注第14行,这一行相当关键,注定了我们的结果最终是<Script> ;然后是构造Script片段,第95行在Head中添加该片段,修成正果;

不仅仅是jQuery,很多js框架都是用了同样的跨域方案,:)说到这里,嗯,这就是getJSON跨域的原理,赵本山说了“情况呢就是这么个情况”

时间: 2024-09-17 04:25:36

ajax跨域访问 JQuery的跨域详解的相关文章

oracle跨库查询dblink的用法实例详解_oracle

本文实例讲述了oracle跨库查询dblink的用法.分享给大家供大家参考,具体如下: 1.创建之前的工作 在创建dblink之前,首先要查看用户是否有相应的权限.针对特定的用户,使用 sqlplus user/pwd登录后,执行如下语句: 复制代码 代码如下: select * from user_sys_privs t where t.privilege like upper('%link%'); 在sys用户下,显示结果为: SYS CREATE DATABASE LINK NO SYS

C#多线程、跨线程与线程安全的示例详解

C#多线程.跨线程与线程安全的示例详解(三种不同方法)  代码如下 复制代码 using System.Threading; public static class Extensions     {         //控件扩展方法(用于跨线程操作),因为为了线程的安全,防止资源竞争出现死锁或不一致的状态,.NET是不允许进行跨线程访问窗体控件的.         public static void SafeCall(this Control ctrl, Action callback)   

jQuery的deferred对象详解

jQuery的开发速度很快,几乎每半年一个大版本,每两个月一个小版本. 每个版本都会引入一些新功能.今天我想介绍的,就是从jQuery 1.5.0版本开始引入的一个新功能----deferred对象. 这个功能很重要,未来将成为jQuery的核心方法,它彻底改变了如何在jQuery中使用ajax.为了实现它,jQuery的全部ajax代码都被改写了.但是,它比较抽象,初学者很难掌握,网上的教程也不多.所以,我把自己的学习笔记整理出来了,希望对大家有用. 本文不是初级教程,针对的读者是那些已经具备

jQuery Validate验证框架详解

版本信息: /*! * jQuery Validation Plugin v1.14.0 * * http://jqueryvalidation.org/ * * Copyright (c) 2015 Jörn Zaefferer * Released under the MIT license */   一.导入js库 <script type="text/javascript" src="validate/jquery-1.6.2.min.js">&

jQuery unbind()方法实例详解_jquery

本文实例讲述了jQuery unbind()方法使用方法.分享给大家供大家参考,具体如下: jQuery 中的 unbind() 方法是 bind() 方法的反向操作,从每一个匹配的元素中删除绑定的事件. 语法结构: 复制代码 代码如下: unbind([type][, data]); type是事件类型,data为将要移除的事件.具体说明如下: 1.如果没有参数,则删除所有的绑定事件: 2.如果提供了事件类型(type)作为参数,则只删除该类型的绑定事件: 3.如果把在绑定时传递的处理函数作为

jQuery Validate验证框架详解(推荐)_jquery

jQuery Validate 插件为表单提供了强大的验证功能,让客户端表单验证变得更简单,同时提供了大量的定制选项,满足应用程序各种需求. 一.导入js库 <script type="text/javascript" src="<%=path %>/validate/jquery-1.6.2.min.js"></script> <script type="text/javascript" src=&qu

jQuery stop()用法实例详解_jquery

近期查看前辈的代码,发现在使用animate()的时候前面需要加上stop(),来防止移进移出的闪动问题,但却不知道stop()里面参数的真正意思,今天查了下stop()中参数的意义和具体使用方法,分享给大家. stop(true)等价于stop(true,false): 停止被选元素的所有加入队列的动画. stop(true,true):停止被选元素的所有加入队列的动画,但允许完成当前动画. stop()等价于stop(false,false):停止被选元素当前的动画,但允许完成以后队列的所有

jQuery siblings()用法实例详解_jquery

siblings() 获得匹配集合中每个元素的同胞,通过选择器进行筛选是可选的. jQuery 的遍历方法siblings() $("给定元素").siblings(".selected") 其作用是筛选给定的同胞同类元素(不包括给定元素本身) 例子:网页选项栏 当点击任意一个选项卡是,其他2个选项卡就会改变样式,其内容也会隐藏. 下面是html代码. <body> <ul id="menu"> <li class=

JavaScript中子对象访问父对象的方式详解_javascript技巧

在传统面向对象的编程语言里,都会提供一种子类访问父类的特殊语法,引文我们在实现子类方法往往需要父类方法的额外辅助.在这种情况下,子类通常会调用父类中的同名方法,最终以便完成工作. javascript虽然没有类似上述的特殊语法,但我们可以造一个啊! function her(){}; her.prototype.name = 'Anna'; her.prototype.toString = function(){ var const = this.constructor; return cons