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

Som*_*one 411 jquery jsonp

我知道JSONPJSON填充.

我理解JSON是什么,以及如何使用它jQuery.getJSON().但是,我不明白callback引入JSONP时的概念.

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

Mat*_*att 765

前言:

这个答案已有六年多了.虽然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();
Run Code Online (Sandbox Code Playgroud)

JSONP请求:

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

document.getElementsByTagName("head")[0].appendChild(tag);
Run Code Online (Sandbox Code Playgroud)

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

JSON:

{ "bar": "baz" }
Run Code Online (Sandbox Code Playgroud)

JSONP:

foo( { "bar": "baz" } );
Run Code Online (Sandbox Code Playgroud)

这就是您看到包含该callback参数的JSONP请求的原因,以便服务器知道要包装响应的函数的名称.

此功能必须存在于全球范围内的时间<script>标记是由浏览器进行评估(一旦请求已完成).


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

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


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

默认情况下,jQuery要求您包含&callback=?在AJAX请求的URL中.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();
Run Code Online (Sandbox Code Playgroud)

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);
Run Code Online (Sandbox Code Playgroud)

  • 这个解释属于博物馆!所有关于@Matt的最佳工作原理解释jsonp.说真的,花了一整天阅读的东西,这是迄今为止最好的. (14认同)
  • 本质上不仅可以从外部Web服务器请求_data_,现在_foreign_ Web服务器可以自动将**任何**脚本注入到网页中,并且客户端甚至无法查看代码它被执行了!将`JSON.parse`替换为'eval`以获得安全性还有很长的路要走. (11认同)
  • @AndrewSavinykh:你是对的.但是,除了添加"Access-Control-Allow-Origin"标头的服务器之外,还需要[有CORS支持]的浏览器(https://developer.mozilla.org/en-US/docs/Web/HTTP/) Access_control_CORS#Browser_compatibility).IE7没有支持,IE8和9支持`XMLHttpRequest`以外的支持(注意这个答案来自2010年!).鉴于Microsoft不再支持这些浏览器,并且应尽可能使用JSONP,CORS(如果可用)的安全含义. (5认同)
  • 我还不确定JSONP的重点是什么.如果服务器可以肯定地添加填充,它也可以在响应上放置Access-Control-Allow-Origin标头? (3认同)

sje*_*397 73

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

{'field': 'value'}
Run Code Online (Sandbox Code Playgroud)

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

myCallback({'field':'value'})
Run Code Online (Sandbox Code Playgroud)

...它不仅仅是一个对象,而且实际上是可以执行的代码.因此,如果您在页面的其他位置定义了一个函数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
  }
});
Run Code Online (Sandbox Code Playgroud)

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

  • 嗯,这最后很明显;) (7认同)

Ada*_*ner 17

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

在此输入图像描述

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

$.get('otherdomain.com', function (response) {
  var name = response.name;
  alert(name);
});
Run Code Online (Sandbox Code Playgroud)

但是,由于请求将发送到其他域,因此无法使用.

我们可以使用<script>标签来发出请求.双方<script src="otherdomain.com"></script>$.get('otherdomain.com')会导致相同的请求而作出:

GET otherdomain.com
Run Code Online (Sandbox Code Playgroud)

问:但如果我们使用<script>标签,我们如何才能访问响应?如果我们想要alert它,我们需要访问它.

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

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

答:那我们就无法使用它了.JSONP要求服务器合作.

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

答:像jQuery 这样的让它变得更好.例如:

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

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

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

答:那么JSONP将不适合我们.

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

答:实际上,它并不那么棒.这真的只是一个黑客.并且它不是最安全的使用方法.既然CORS可用,您应该尽可能使用它.