繁体   English   中英

有人能用外行人解释什么是JSONP吗? [重复]

[英]Can anyone explain what JSONP is, in layman terms? [duplicate]

这个问题已经在这里有了答案:

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

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


使用jQuery

使用jQuery发出JSONP请求的有用之处在于,jQuery在后台为您完成了所有工作

默认情况下,jQuery要求您包含&callback=? 在您的AJAX请求的网址中。 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);

假设您有一些可以提供JSON数据的URL,例如:

{'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请求不同,您不受限于从与页面相同来源获取数据。

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返回给我们怎么办?

答:那么我们将无法使用它。 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非常棒,我将继续使用它-谢谢!

答:其实不是那么棒。 它实际上只是一个hack。 而且它不是最安全的使用方法。 现在CORS可用了,您应该尽可能使用它。

我找到了一篇有用的文章,该文章也非常清晰易懂地解释了该主题。 链接为JSONP

一些值得注意的要点是:

  1. JSONP早于CORS。
  2. 这是从不同域检索数据的伪标准方法,
  3. 它具有有限的CORS功能(仅GET方法)

工作方式如下:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM