AJAX 跨域请求获取 JSON 数据 | JSONP 原理及 jQuery/MooTools/Dojo 实现

🕒 2026-01-26 15:42:29
📁 JSON学习教程
作者:JSONLA小编

Asynchronous JavaScript and XML (AJAX) 是驱动新一代 Web 站点(流行术语为 Web 2.0 站点)的关键技术。Ajax 允许在不干扰 Web 应用程序的显示和行为的情况下在后台进行数据检索。使用 XMLHttpRequest 函数获取数据,它是一种 API,允许客户端 JavaScript 通过 HTTP 连接到远程服务器。Ajax 也是许多 mashup 的驱动力,它可将来自多个地方的内容集成为单一 Web 应用程序。 我们都知道,由于受到浏览器的同源策略限制,AJAX 是不允许跨域请求。不过可以通过使用 JSONP 来实现。JSONP 是一种通过脚本标记注入的方式,它是可以引用跨域 URL 的 js 脚本,不过需要提供一个回调函数(必须在您自己的页面上),因此,你可以自己处理结果。 

一、jQuery 的 JSONP

1. 什么是 JSONP

要了解 JSONP,不得不提一下 JSON,那什么是 JSON? JSON is a subset of the object literal notation of JavaScript. Since JSON is a subset of JavaScript, it can be used in the language with no muss or fuss.JSONP (JSON with Padding) 是一个非官方的协议,它允许在服务器端集成 Script tags 返回至客户端,通过 javascript callback 的形式实现跨域访问(这仅仅是 JSONP 简单的实现形式)。

核心原理

JSONP 能实现跨域的核心原因是:浏览器的同源策略仅限制 XMLHttpRequest/AJAX 请求,而<script>标签的 src 属性不受同源策略约束。其本质是通过动态创建<script>标签请求跨域接口,服务端将 JSON 数据包裹在前端指定的回调函数中返回,前端通过预定义回调函数解析数据。

关键区别:AJAX 是 “请求数据”,JSONP 是 “加载脚本并执行”,这是 JSONP 能跨域的根本原因。 

2. JSONP 有什么用

由于同源策略的限制,XmlHttpRequest 只允许请求当前源(域名、协议、端口三者一致)的资源,为了实现跨域请求,可以通过 script 标签实现跨域请求,然后在服务端输出 JSON 数据并执行回调函数,从而解决了跨域的数据请求。

JSONP 局限性

JSONP 虽能解决跨域,但存在天然限制,开发中需注意:

  1. 仅支持GET 请求(因<script>标签仅能发起 GET 请求),无法实现 POST/PUT/DELETE 等请求;
  2. 无错误处理机制(无法捕获跨域请求的 404/500 等错误);
  3. 存在 XSS 安全风险(若服务端返回恶意脚本,会直接执行);
  4. 依赖服务端配合(需服务端支持回调函数参数解析和数据包裹)。

jQuery.getJSON 方法

jQuery 封装了便捷的 JSONP 调用方法,$.getJSON是最简洁的方式,只需在 URL 后拼接callback=?,jQuery 会自动生成随机回调函数名并完成后续处理: 

Js 代码如下:

   jQuery.getJSON("http://search.twitter.com/search.json?callback=?",{ 

    q: "Arsenal" 

},function(tweets) { 

    // Handle response here 

    console.info("Twitter returned: ",tweets); 

});

代码解析

  • callback=?:jQuery 的占位符,会自动替换为如jQuery112407345678901234567_1690000000的随机回调函数名,避免全局函数名冲突;
  • 第二个参数:请求参数对象,jQuery 会自动拼接为 URL 参数(如?q=Arsenal&callback=xxx);
  • 第三个参数:成功回调函数,直接接收服务端返回的 JSON 对象,无需手动解析。

jQuery.ajax 完整配置方式

若需要更灵活的配置(如自定义回调函数参数名、设置超时等),可使用$.ajax方法并指定dataType: "jsonp",这是 jQuery 中 JSONP 的通用实现方式: 

Js 代码如下:

  $.ajax({ 

         type:"get", 

         data:"random = "+Math.random(), 

         url:url, 

         dataType:"jsonp", 

         jsonp:"callback", 

         success:function(data){ 

         $.each(data, function(key, val) { 

         $("#myDiv").html($("#myDiv").html()+val.cvalue+"</br>"); 

         }); 

        } 

      }); 

  回调方法的参数通过 getJSON 就可以获取到 json 对象

关键配置解析

  • jsonp: "callback":告诉 jQuery,服务端接收回调函数名的参数是callback,若服务端要求jsoncallback,则需改为jsonp: "jsoncallback";
  • jsonpCallback:手动指定回调函数名,适用于需要固定函数名的场景,默认省略时 jQuery 自动生成,推荐使用默认值避免全局冲突;
  • cache: false:可替代Math.random(),jQuery 会自动添加_=时间戳参数防止缓存,更简洁。

二、MooTools JSONP

MooTools 本身核心库未集成 JSONP 功能,需要引入Request.JSONP Class,该类在 MooTools More 扩展库中,可以从这里下载 MooTools More。选择 Request.JSONP 模块引入后,从另一个域获取 JSON 就是小菜一碟了

MooTools JSONP 实现代码

Js 代码如下:

new Request.JSONP({ 

    url: "http://search.twitter.com/search.json", 

    data: { 

        q: "Arsenal" 

    },//提交的参数, 没有参数可以不写 

        callbackKey: 'jsoncallback',//自己定义回调函数的参数名称 

        onComplete: function(tweets) { 

        // Log the result to console for inspection 

        console.info("Twitter returned: ",tweets); 

    } 

}).send(); 

  如果自己定义了回调函数的参数名称,跟 jquery 一样,服务端需要对应解析该参数名。

MooTools JSONP 对应的服务端适配代码

服务器端你需要这样去取得回调函数名并包裹数据: 

Js 代码如下: 

String callback = request.getParameter("jsoncallback");//取得回调方法名 

        response.setHeader("Cache-Control", "no-cache"); 

        response.setContentType("text/json;charset = UTF-8"); 

        PrintWriter out; 

        try { 

            out = response.getWriter(); 

            out.print(callback+"("+message+")");//这里是关键.主要就是这里 

            out.flush(); 

            out.close(); 

        } catch (IOException e) { 

            e.printStackTrace(); 

        } 

三、Dojo JSONP

JSONP 在 Dojo Toolkit 中需要用上 dojo.io.script 模块(点击可以查看示例),该模块是 Dojo 专门用于处理跨域脚本加载的核心模块,支持 JSONP 实现,使用前需先引入该模块。

Dojo JSONP 实现代码

Js 代码如下:

// dojo.io.script is an external dependency, so it must be required 

dojo.require("dojo.io.script"); 


// When the resource is ready 

dojo.ready(function() { 


    // Use the get method 

    dojo.io.script.get({ 

        // The URL to get JSON from Twitter 

        url: "http://search.twitter.com/search.json", 

        // The callback paramater 

        callbackParamName: "callback", // Twitter requires "callback" 

        // The content to send 

        content: { 

            q: "Arsenal" 

        }, 

        // The success callback 

        load: function(tweetsJson) {  // Twitter sent us information! 

            // Log the result to console for inspection 

            console.info("Twitter returned: ",tweetsJson); 

        } 

    }); 

}); 

Dojo JSONP 关键特性

  1. 需通过dojo.require显式引入依赖模块,符合 Dojo 的模块化设计思想;
  2. 提供error回调函数,是少数自带 JSONP 错误处理的框架(仅能捕获脚本加载失败,无法捕获服务端业务错误);
  3. callbackParamName与 jQuery 的jsonp、MooTools 的callbackKey功能一致,均用于指定服务端回调参数名。

四、JSONP 核心总结

JSONP 是一种非常有效的,可靠的,容易实现的远程数据获取方式。JSONP 的策略也使开发人员能够避免繁琐的服务器代理方式,很方便的获取数据。 JSONP (JSON with Padding) 是一个非官方的协议,它允许在服务器端集成 Script tags 返回至客户端,通过 javascript callback 的形式实现跨域访问(这仅仅是 JSONP 简单的实现形式)。

五、原生 JavaScript 实现 JSONP(无框架依赖)

以上框架均是对原生 JSONP 的封装,理解原生实现能更深入掌握 JSONP 的核心逻辑,原生实现无需依赖任何框架,仅通过动态创建<script>标签即可完成,分为客户端自定义回调函数服务端数据包裹两部分。

客户端原生代码 

<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />  

  <script type="text/javascript">  

    function jsonpCallback(result) {  

      //alert(result);  

      for(var i in result) {  

        alert(i+":"+result[i]);  //循环输出a:1, b:2, etc.  

      }  

    }  

    var JSONP=document.createElement("script");  

    JSONP.type = "text/javascript";  

    JSONP.src = "http://crossdomain.com/services.php?callback = jsonpCallback";  

    document.getElementsByTagName("head")[0].appendChild(JSONP);  

  </script>

原生实现关键步骤解析

  1. 预定义回调函数:必须在全局作用域定义,因为动态加载的脚本会在全局执行,局部函数无法被访问;
  2. 动态创建 script 标签:避免页面加载时直接发起请求,可根据业务逻辑按需创建;
  3. 拼接回调函数参数:必须明确指定callback=回调函数名,服务端需严格解析该参数;
  4. 加入 DOM 触发请求:将 script 标签加入 head/body 后,浏览器会立即发起 GET 请求。

服务端原生适配代码(PHP 版)

服务端需要接收前端传入的回调函数名,将 JSON 数据包裹后返回,以下是 PHP 实现的服务端代码,其他语言(Java/Node.js/Python)逻辑一致:

<?php  

  

    //服务端返回 JSON 数据  

    $arr=array('a'=>1,'b'=>2,'c'=>3,'d'=>4,'e'=>5);  

    $result=json_encode($arr);  

    //echo $_GET['callback'].'("Hello,World!")';  

    //echo $_GET['callback']."($result)";  

    //动态执行回调函数  

    $callback = $_GET['callback'];  

    echo $callback."($result)";

相关推荐

正在加载... ...