JSON和JSONP有什么区别?

413

在格式、文件类型和实际使用方面,有何不同?


14
请看请解释JSONP - Matthew Flaschen
4
其中一种方法比另一种更快吗? 例如,如果您使用XMLHttpRequest来GET请求(显然是对相同域的“普通”ajax请求),或者使用JSONP方法(它不会使用XMLHTTPRequest)- 是否有一种方法比另一种更快?我知道这取决于几个因素 - 但是否有人进行了速度比较? - Yuval A.
8个回答

420

JSONP是带有填充的JSON。也就是说,你在开头放置一个字符串,然后用括号把它括起来。例如:

//JSON
{"name":"stackoverflow","id":5}
//JSONP
func({"name":"stackoverflow","id":5});

结果是您可以将JSON作为脚本文件加载。如果您之前设置了一个名为func的函数,那么当脚本文件加载完成时,该函数将使用一个参数(即JSON数据)进行调用。这通常用于允许跨站点使用JSON数据的AJAX。如果您知道example.com正在提供类似于上面给出的JSONP示例的JSON文件,则可以使用以下代码检索它,即使您不在example.com域上也可以:

function func(json){
  alert(json.name);
}
var elm = document.createElement("script");
elm.setAttribute("type", "text/javascript");
elm.src = "http://example.com/jsonp";
document.body.appendChild(elm);

5
如果您可以配置CORS以允许跨域请求,那么JSONP还有意义吗? - Josh Hibschman
2
也许有点晚了,但我仍然想回答你的问题,以便其他人参考。如果你使用JSONP,那么你就放弃了所有CORS的优势(我之所以称之为优势是因为涉及到安全问题)。我建议你正确实现CORS,这将有助于解决安全问题,并且在架构上更加合理。 - Dogan

113

基本上,由于同源策略,您无法通过AJAX从另一个域请求JSON数据。AJAX允许您在页面加载后获取数据,然后一旦返回数据就执行一些代码/调用函数。我们不能使用AJAX,但是可以将<script>标签注入到我们自己的页面中,并且这些标签允许引用托管在其他域上的脚本。

通常,您会使用CDN(如jQuery)包含库。然而,我们可以滥用此技术来获取数据!JSON已经是有效的JavaScript(大部分情况下是这样),但是我们不能直接在脚本文件中返回JSON,因为我们没有办法知道脚本/数据何时加载完成,也没有办法访问它,除非将其分配给变量或传递给函数。因此,我们告诉网络服务,在准备好时代表我们调用一个函数。

例如,我们可能会从股票交易API请求一些数据,并且除了通常的API参数外,我们还提供了一个回调,例如?callback=callThisWhenReady。网络服务然后使用我们的函数包装数据,并像这样返回: callThisWhenReady({...data...})。现在脚本加载后,您的浏览器将尝试执行它(与正常情况一样),这将调用我们的任意函数并提供所需的数据。

它与正常的AJAX请求非常相似,只是不是调用匿名函数,而是必须使用命名函数。

jQuery通过为您创建唯一命名的函数并将其传递,以便无缝支持此功能,然后将运行您想要的代码。


2
分离自什么?JSON也不是一种语言。 - nickf
6
是的,我在寻找正确的词语...那么你会怎么称呼它呢?根据json.org,应该称之为“数据交换格式”。 - mpen
JSON:一种“文本表示法”中的JavaScript对象。就像您可能会toString()一个Java对象一样? - Sam Vloeberghs
FWIW:@SamVloeberghs - 说JSON代表JavaScript对象有点误导人。它可以是任何数据,来自任何语言或数据库,可表示为名称-值对和数组。并且需要其他约定才能准确地往返于任何JS对象 - 参见JSON:不支持的本机数据类型。值得注意的是,JS日期在最后以字符串形式返回。 https://weblog.west-wind.com/posts/2014/jan/06/javascript-json-date-parsing-and-real-dates - ToolmakerSteve

70

JSONP 允许您指定一个回调函数来传递您的 JSON 对象。这样,您就可以绕过同源策略,并将来自外部服务器的 JSON 加载到您网页上的 JavaScript 中。


32

JSONP代表“带填充的JSON”,它是解决从不同域加载数据的方法。它将脚本加载到DOM头部,因此您可以像在自己的域上加载信息一样访问信息,从而绕过跨域问题。

jsonCallback(
{
    "sites":
    [
        {
            "siteName": "JQUERY4U",
            "domainName": "http://www.jquery4u.com",
            "description": "#1 jQuery Blog for your Daily News, Plugins, Tuts/Tips &amp; Code Snippets."
        },
        {
            "siteName": "BLOGOOLA",
            "domainName": "http://www.blogoola.com",
            "description": "Expose your blog to millions and increase your audience."
        },
        {
            "siteName": "PHPSCRIPTS4U",
            "domainName": "http://www.phpscripts4u.com",
            "description": "The Blog of Enthusiastic PHP Scripters"
        }
    ]
});

(function($) {
var url = 'http://www.jquery4u.com/scripts/jquery4u-sites.json?callback=?';

$.ajax({
   type: 'GET',
    url: url,
    async: false,
    jsonpCallback: 'jsonCallback',
    contentType: "application/json",
    dataType: 'jsonp',
    success: function(json) {
       console.dir(json.sites);
    },
    error: function(e) {
       console.log(e.message);
    }
});

})(jQuery);
现在,我们可以通过使用JSONP和我们创建的回调函数来通过AJAX请求JSON。输出应该是JSON作为对象,然后我们可以自由地使用数据而没有任何限制。

20

JSONP本质上是带有额外代码的JSON,就像一个函数调用包裹在数据周围。它允许在解析期间对数据进行操作。


14

JSON

JSON(JavaScript对象表示法)是在应用程序之间传输数据的方便方法,尤其是当目的地是JavaScript应用程序时。

示例:

这是一个使用JSON作为服务器响应传输的最简示例。客户端使用jQuery简写函数$.getJSON进行Ajax请求。服务器生成哈希值,将其格式化为JSON并将其返回给客户端。客户端将其格式化并放入页面元素中。

服务器:

get '/json' do
 content_type :json
 content = { :response  => 'Sent via JSON',
            :timestamp => Time.now,
            :random    => rand(10000) }
 content.to_json
end

客户:

var url = host_prefix + '/json';
$.getJSON(url, function(json){
  $("#json-response").html(JSON.stringify(json, null, 2));
});

输出:

  {
   "response": "Sent via JSON",
   "timestamp": "2014-06-18 09:49:01 +0000",
   "random": 6074
  }

JSONP(带填充的 JSON)

JSONP 是在客户端从不同域向服务器发送 JSON 响应时,克服浏览器限制的简单方法。

在客户端使用 JSONP 的唯一变化是将回调参数添加到 URL 中。

服务器:

get '/jsonp' do
 callback = params['callback']
 content_type :js
 content = { :response  => 'Sent via JSONP',
            :timestamp => Time.now,
            :random    => rand(10000) }
 "#{callback}(#{content.to_json})"
end

客户:

var url = host_prefix + '/jsonp?callback=?';
$.getJSON(url, function(jsonp){
  $("#jsonp-response").html(JSON.stringify(jsonp, null, 2));
});

输出:

 {
  "response": "Sent via JSONP",
  "timestamp": "2014-06-18 09:50:15 +0000",
  "random": 364
}

7
“JSONP是带有额外代码的JSON”对于现实世界来说太简单了。不,你必须有一些小差异。如果一切都“只是工作”,编程有什么乐趣呢?
事实证明,JSON不是JavaScript的子集。如果你只是将一个JSON对象包装在一个函数调用中,总有一天你会被奇怪的语法错误所困扰,就像我今天一样。

1

JSONP是在客户端从不同域发送JSON响应时克服浏览器限制的简单方法。

但是,这种方法的实际实现涉及微妙的差异,通常没有清楚地解释。

这里有一个简单的教程,展示了JSON和JSONP并排的效果。

所有代码都可在Github上自由获取,live版本可在http://json-jsonp-tutorial.craic.com找到。


1
那个链接已经失效。 - ChrisDeDavidMindflowAU

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接