JSONP 原理详解:跨域实现、jQuery 封装与 JSON/Ajax 区别
本文深入解析 JSONP 跨域原理,指出其核心是利用 script 标签不受同源策略限制的特性。详细对比了 JSON 数据格式与 JSONP 协议的区别,以及 Ajax 基于 XMLHttpRequest 与 JSONP 基于动态脚本加载的差异。同时涵盖 jQuery 对 JSONP 的封装机制、回调函数处理及常见使用注意事项。
JSONP 概述与背景
前言
初次接触 JSONP 是在两年前,当时负责开发活动页面的抽奖模块,需要从服务端获取概率数据。由于缺乏经验,同事建议使用 Ajax,我便照做;当同事提示将 dataType 修改为 jsonp 时,我也直接修改。活动页面完成后,很长一段时间内未再遇到 JSONP,期间我一直误以为它与 Ajax 紧密相关,是 XMLHttpRequest(XHR)的一种特殊跨域形式。直到一个月前面试中被问及 JSONP 而表现不佳,我才决定深入研究。实际上,JSONP 的原理并不复杂。
JSONP 的应用场景与原理
为什么要用 JSONP?
大家对跨域和同源策略应该不陌生。如果对此感到困惑,不妨从基础概念重新梳理,以便深入浅出地理解。
假设编写了一个 index 页面,其中包含一个请求 JSON 数据的接口(若不了解 JSON,可参考相关简介与用法汇总)。经过简单思考,代码如下:
<script src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
<script type="text/javascript">
$.ajax({
url: 'http://localhost/a.json',
dataType: "json",
success: function (data) {
console.log(data);
}
})
</script>
{
"name": "hanzichi",
"age": 10
}
作者将两个文件均放置在 WAMP 服务器的 www 目录下,由于 Ajax 请求未涉及跨域,因此能够完美获取结果:

然而,如果 JSON 文件与 index 文件位于不同的域下,即发生跨域(关于跨域概念,可参考 JavaScript 同源策略),情况会如何呢?
尝试在 WAMP 中开启一个新的 Apache 端口(参考多端口访问配置),并将 JSON 文件放置在该端口对应的文件夹下(作者设置端口为 8080,默认端口为 80),尝试发送请求:
<script src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
<script type="text/javascript">
$.ajax({
url: 'http://localhost:8080/a.json',
dataType: "json",
success: function (data) {
console.log(data);
}
})
</script>

结果显然提示跨域错误!该如何解决?此时 JSONP 便派上用场。
利用 Script 标签实现跨域
神奇的 script 标签
JSONP 与 script 标签密切相关,而与 XHR 或传统意义上的 Ajax 并无直接关联。
回顾上述 index.html 代码,页面引用了百度 CDN 的 jQuery 路径。这种用法已司空见惯,但仔细思考会发现,script 标签本身是完全支持跨域的。没错,JSONP 的核心实现正是利用了 script 标签的跨域能力。因此,我们可以动态生成一个 script 标签,将 JSON 的 URL 赋值给其 src 属性,随后将该标签插入 DOM 中。
<body>
<script src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
<script type="text/javascript">
var s = document.createElement('script');
s.src = 'http://localhost:8080/a.json';
document.body.appendChild(s);
</script>
</body>
我们创建了一个 script 标签,其内部包裹的内容正是所需的 JSON 数据,但执行时报错如下:

原因在于 JSON 数据并非合法的 JavaScript 语句。最简单的方法是将上述 JSON 数据包裹在一个回调函数中:
<body>
<script src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
<script type="text/javascript">
function jsonpcallback(json) {
console.log(json);
}
var s = document.createElement('script');
s.src = 'http://localhost:8080/a.json';
document.body.appendChild(s);
</script>
</body>
jsonpcallback({
"name": "hanzichi",
"age": 10
});

此时,a.json 文件的命名并非必须如此,即使将其重命名为 a.js 也不会产生任何问题。
若需与服务器端交互,原理相同。例如与 PHP 交互:
<body>
<script src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
<script type="text/javascript">
function jsonpcallback(json) {
console.log(json);
}
var s = document.createElement('script');
s.src="http://localhost:8080/test.php?callback=jsonpcallback";
document.body.appendChild(s);
</script>
</body>
<?php
$jsondata = '{
"name": "hanzichi",
"age": 10
}';
echo $_GET['callback'].'('.$jsondata.')';
?>
需要注意的是,JSONP 提供的 URL(即动态生成的 script 标签的 src 属性),无论其表面形式如何,最终返回的都是一段 JavaScript 代码。
jQuery 对 JSONP 的封装与使用
jQuery 对 JSONP 的封装
为了简化开发,jQuery 对 JSONP 进行了封装,并将其集成在 Ajax 方法中。
<script src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
<script type="text/javascript">
$.ajax({
url: 'http://localhost:8080/a.json',
dataType: 'jsonp',
jsonpCallback: 'CallBack',
success: function (data) {
console.log(data);
}
});
</script>
CallBack({
"name": "hanzichi",
"age": 10
});
上述代码针对的是请求文件中已写死 callback 函数名的情况。由于请求的是 JSON 文件,JSON 本身不是服务器端动态语言,无法进行解析;如果是 PHP 或其他服务器端语言,则无需写死函数名,例如:
<script src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
<script type="text/javascript">
$.ajax({
url: 'http://localhost:8080/test.php',
dataType: 'jsonp',
success: function (data) {
console.log(data);
}
});
</script>
<?php
$jsondata = '{
"name": "hanzichi",
"age": 10
}';
echo $_GET['callback'].'('.$jsondata.')';
?>
当然,类似的封装方法还有几种:
// 1
$.getJSON("http://localhost:8080/test.php?callback=?", function(data) {
console.log(data);
});
// 2
$.get('http://localhost:8080/test.php', function(data) {
console.log(data);
}, 'jsonp');
需要注意的是,使用 getJSON 方法时,请求地址 URL 中必须包含 callback=?。因为 jQuery 对该方法进行了封装,默认回调函数变量名并非 callback,导致 PHP 中的 $_GET['callback'] 无法获取变量值。
而一般的 jQuery 方法 URL 中无需指定 callback 参数。对于 jQuery 中的 JSONP,callback 参数是自动添加的。默认情况下,jQuery 生成的 JSONP 请求中 callback 参数形如 callback=jQuery200023559735575690866_1434954892929,这是一种看似随机生成的名称,对应的是 success 处理函数,因此通常无需特别处理。如果要写死 callback 名称,可参考上文。

JSONP 核心原理总结
总结
受同源策略限制,XmlHttpRequest 仅允许请求当前源(域名、协议、端口)的资源。为实现跨域请求,可通过 script 标签实现跨域请求,并在服务端输出 JSON 数据以执行回调函数,从而解决跨域数据请求问题,这就是 JSONP 的核心。
JSONP 原理:
1. 首先在客户端注册一个 callback,并将该 callback 的名字传给服务器。 2. 服务器先生成 JSON 数据,然后以 JavaScript 语法的方式生成一个 function,function 的名字即为传递上来的参数 jsonp。最后将 JSON 数据直接作为入参放置到 function 中,从而生成一段 JavaScript 语法的文档并返回给客户端。 3. 客户端浏览器解析 script 标签,并执行返回的 JavaScript 文档,此时数据作为参数传入客户端预先定义好的 callback 函数中(动态执行回调函数)。
JSON、JSONP 与 Ajax 的区别对比
JSON 和 JSONP 的区别,以及 Ajax 和 JSONP 的区别
JSON 和 JSONP 虽然仅有一个字母之差,但二者之间并无直接关系。
JSON 是一种轻量级的数据交换格式。
JSONP 是一种跨域数据交互协议。
JSON 的优点包括:(1)基于纯文本传递,极其简单;(2)轻量级数据格式,适合互联网传递;(3)易于编写和解析。
Ajax 和 JSONP 的区别:
相同点:都是请求一个 URL。
不同点:Ajax 的核心是通过 XMLHttpRequest 获取内容。
JSONP 的核心则是动态添加 <script> 标签来调用服务器提供的 JavaScript 脚本。
ES6模块化中js文件怎么用import和export交互
2026-11-05 17:00:48
JS读取本地文件时报错或无响应的常见原因
2026-11-05 16:32:31
let、const与var的区别:JavaScript变量声明最佳实践
2026-11-05 14:16:38
JS中直接定义静态二维数组的字面量写法
2026-11-05 14:16:08
JS 怎么查找字符串中所有匹配项的位置
2026-11-05 14:15:53
