任何人都可以用通俗的话来解释JSONP是什么?

我知道JSONP是带填充的JSON

我了解JSON是什么,以及如何将它与jQuery.getJSON()一起使用。 但是,在引入JSONP时,我不明白callback的概念。

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


前言:

这个答案已经六年多了。 尽管JSONP的概念和应用没有改变(即答案的细节仍然有效),但您应该尽可能使用CORS(即您的服务器或API支持它,并且浏览器支持是足够的),因为JSONP具有固有的安全风险。


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响应之间需要注意的另一个区别是,可以通过在try / catch语句中包装评估responseText的尝试来捕获JSON响应中的任何解析错误。 由于JSONP响应的本质,解析响应中的错误将导致无法解析的JavaScript解析错误。

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


使用jQuery创建JSONP请求的实用性在于jQuery在后台为您完成了所有工作

默认情况下,jQuery要求你包含&callback=? 在您的AJAX请求的网址中。 jQuery将采用您指定的success函数,为其分配一个唯一的名称,并将其发布到全局范围中。 它会替换问号? in &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);

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

{'field': 'value'}

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

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

......这不仅仅是一个对象,而是实际上可以执行的代码。 因此,如果您在页面的其他地方定义一个名为myFunction的函数并执行该脚本,则会使用URL中的数据调用该函数。

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

这是jQuery在做出ajax请求时的做法(使用带'jsonp'的.ajax作为dataType属性的值)。 例如

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

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


JSONP是避开浏览器的同源策略的一种方式。 怎么样? 喜欢这个:

在这里输入图像描述

这里的目标是向otherdomain.com发出请求并在响应中alert该名称。 通常我们会发出一个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进行响应,以JavaScript响应作为参数调用我们的函数。

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

A:那我们将无法使用它。 JSONP要求服务器进行合作。

问:不得不使用<script>标签很难看。

答:像jQuery这样的库使它更好。 例如:

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

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

问: <script>标签只会产生GET请求 - 如果我们想发出POST请求会怎么样?

答:那么JSONP不适合我们。

问:没关系,我只想提出GET请求。 JSONP真棒,我会去使用它 - 谢谢!

A:其实并不是那么棒。 这真的只是一个黑客。 这不是最安全的使用方法。 现在CORS可用,您应该尽可能使用它。

链接地址: http://www.djcxy.com/p/1289.html

上一篇: Can anyone explain what JSONP is, in layman terms?

下一篇: How to pretty print XML from the command line?