用外行人的话可以解释一下JSONP是什么吗?

时间:2010-10-01 14:13:56

标签: jquery jsonp

我知道JSONP是带有填充的JSON

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

任何人都可以向我解释这是如何运作的吗?

4 个答案:

答案 0 :(得分:761)

前言

这个答案已有六年多了。虽然JSONP的概念和应用没有改变 (即答案的细节仍然有效),你应该 look to use CORS where possible (即你的serverAPI支持它,并支持它 browser support已足够), 作为JSONP has inherent security risks


JSONP(带有填充的 JSON )是一种常用的方法 绕过Web浏览器中的跨域策略。 (您不允许向浏览器认为位于不同服务器上的网页发出AJAX请求。)

JSON和JSONP在客户端和服务器上的行为方式不同。不使用XMLHTTPRequest和关联的浏览器方法调度JSONP请求。而是创建<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" } );

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

此功能必须存在于全局范围 浏览器评估<script>标记(一旦请求完成)。


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

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


使用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);

答案 1 :(得分:73)

假设您有一些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属性的值)。 E.g。

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

这里,jQuery负责回调函数名称和查询参数 - 使API与其他ajax调用相同。但与上面提到的其他类型的ajax请求不同,您不仅限于从与页面相同的来源获取数据。

答案 2 :(得分:17)

JSONP是一种绕过浏览器same-origin policy的方法。怎么样?像这样:

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,我们需要访问它。

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

问:但是如果服务器不会为我们这样做,并且只愿意将JSON返回给我们呢?

答:然后我们将无法使用它。 JSONP要求服务器合作。

问:必须使用<script>标签很难看。

答:像jQuery make it nicer这样的库。例如:

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

它的工作原理是动态创建<script>标记DOM元素。

问:<script>标记只发出GET请求 - 如果我们想要发出POST请求怎么办?

答:那么JSONP将无法为我们工作。

问:没关系,我只想提出GET请求。 JSONP太棒了,我打算用它 - 谢谢!

答:实际上,它并不那么棒。这真的只是一个黑客。并isn't the safest使用它。现在CORS可用,你应该尽可能使用它。

答案 3 :(得分:2)

我找到了一篇有用的文章,它也非常清楚易懂地解释了这个主题。链接是JSONP

一些值得注意的要点是:

  1. JSONP早于CORS。
  2. 这是一种从其他域中检索数据的伪标准方法,
  3. 它具有有限的CORS功能(仅限GET方法)
  4. 工作如下:

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