有人能用外行的语言解释一下JSONP是什么吗?

我知道JSONP是带有填充的JSON

我了解JSON是什么,以及如何与jQuery.getJSON()一起使用它。然而,在介绍JSONP时,我不理解callback的概念。

谁能给我解释一下这是怎么回事?

146191 次浏览

假设你有一些URL,给你JSON数据,比如:

{'field': 'value'}

...你有一个类似的URL,除了它使用JSONP,你传递回调函数名称'myCallback'(通常通过给它一个名为'callback'的查询参数来完成,例如http://example.com/dataSource?callback=myCallback)。然后它会返回:

myCallback({'field':'value'})

...这不仅仅是一个对象,实际上是可以执行的代码。因此,如果你在页面的其他地方定义了一个名为myFunction的函数并执行这个脚本,它将被来自URL的数据调用。

最酷的事情是:你可以创建一个脚本标记,并使用你的URL(带有callback参数)作为src属性,浏览器将运行它。这意味着您可以绕过“同源”安全策略(因为浏览器允许您从页面域以外的源运行脚本标记)。

这就是jQuery在ajax请求时所做的事情(使用.ajax和'jsonp'作为dataType属性的值)。如。

$.ajax({
url: 'http://example.com/datasource',
dataType: 'jsonp',
success: function(data) {
// your code to handle data here
}
});

这里,jQuery负责回调函数名和查询参数——使API与其他ajax调用相同。但与其他类型的ajax请求不同的是,如前所述,您不局限于从与页面相同的来源获取数据。

前言:

这个答案已经超过6年了。而JSONP的概念和应用并没有改变 (即答案的细节仍然有效),你应该这样做 尽可能使用CORS (即你的服务器API支持它,而 浏览器支持是足够的), as JSONP 具有固有的安全风险.

. as JSONP 具有固有的安全风险. as JSONP
JSONP (带填充的JSON)是一个常用的方法 绕过浏览器中的跨域策略。(您不允许对浏览器认为是在不同服务器上的web页面发出AJAX请求)

JSON和JSONP在客户端和服务器上的行为不同。JSONP请求不是使用XMLHTTPRequest和相关的浏览器方法分派的。相反,会创建一个<script>标记,其源被设置为目标URL。然后将这个脚本标记添加到DOM中(通常在<head>元素中)。

JSON请求:

var xhr = new XMLHttpRequest();


xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
// success
};
};


xhr.open("GET", "somewhere.php", true);
xhr.send();

JSONP请求:

var tag = document.createElement("script");
tag.src = 'somewhere_else.php?callback=foo';


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

JSON响应和JSONP响应之间的区别在于JSONP响应对象作为参数传递给回调函数。

JSON:

{ "bar": "baz" }

JSONP:

foo( { "bar": "baz" } );

这就是为什么你会看到JSONP请求包含callback参数,这样服务器就知道要包装响应的函数的名称。

这个函数必须存在在全局作用域当时中的<script>标记由浏览器计算(一旦请求完成)。


JSON响应和JSONP响应处理之间需要注意的另一个区别是,JSON响应中的任何解析错误都可以通过包装对responseText求值的尝试来捕获 try/catch语句中。由于JSONP响应的性质,响应中的解析错误将导致无法捕捉的JavaScript解析错误

这两种格式都可以通过在初始化请求之前设置超时并在响应处理程序中清除超时来实现超时错误。


使用jQuery

使用jQuery来发出JSONP请求的好处是jQuery会在后台为你执行所有的工作

默认情况下,jQuery要求你在AJAX请求的URL中包含&callback=?。jQuery将接受你指定的success函数,为它分配一个唯一的名称,并将它发布到全局作用域。然后,它将用它分配的名称替换&callback=?中的问号?


可比的JSON/JSONP实现

下面假设一个响应对象{ "bar" : "baz" }

JSON:

var xhr = new XMLHttpRequest();


xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
document.getElementById("output").innerHTML = eval('(' + this.responseText + ')').bar;
};
};


xhr.open("GET", "somewhere.php", true);
xhr.send();

JSONP:

function foo(response) {
document.getElementById("output").innerHTML = response.bar;
};


var tag = document.createElement("script");
tag.src = 'somewhere_else.php?callback=foo';


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

JSONP是一种绕过浏览器同源策略的方法。怎么做?是这样的:

enter image description here

这里的目标是向otherdomain.comalert请求响应中的名称。通常我们会发出一个AJAX请求:

$.get('otherdomain.com', function (response) {
var name = response.name;
alert(name);
});

但是,由于请求将发送到不同的域,因此它将不起作用。

不过,我们可以使用<script>标记来发出请求。<script src="otherdomain.com"></script>$.get('otherdomain.com')都会产生相同的请求:

GET otherdomain.com

问:但是如果我们使用<script>标记,我们怎么能访问响应呢?如果我们想alert它,我们需要访问它。

A:呃,我们不能。但是我们可以这样做——定义一个使用响应的函数,然后告诉服务器用JavaScript响应,用响应作为参数调用我们的函数。

问:但是如果服务器不为我们做这些,只愿意返回JSON给我们怎么办?

A:那我们就不能用了。JSONP要求服务器配合。

问:必须使用<script>标记是丑陋的。

答:jQuery 让它更漂亮等库。例:

$.ajax({
url: "http://otherdomain.com",
jsonp: "callback",
dataType: "jsonp",
success: function( response ) {
console.log( response );
}
});

它通过动态创建<script>标记DOM元素来工作。

Q: <script>标签只做GET请求——如果我们想做POST请求怎么办?

A:那么JSONP对我们不适用了。

问:没关系,我只是想做一个GET请求。JSONP太棒了,我要去用它——谢谢!

A:事实上,它并没有那么棒。这真的只是个黑客。它不是最安全的吗的东西来使用。既然CORS是可用的,您应该尽可能使用它。

我发现了一篇有用的文章,它也很清楚地用简单的语言解释了这个主题。Link是JSONP

一些值得注意的点是:

  1. JSONP早于CORS。
  2. 这是一种从不同领域检索数据的伪标准方法,
  3. 它具有有限的CORS特性(只有GET方法)

工作情况如下:

  1. <script src="url?callback=function_name">包含在html代码中
  2. 当执行第1步时,它会将具有相同函数名(url参数中给出的函数名)的函数作为响应。
  3. 如果代码中存在具有给定名称的函数,则它将与数据一起执行,如果有数据,则作为该函数的参数返回。