什么是JSONP?

我了解JSON,但不是JSONP。 关于JSON的维基百科的文档是(是)JSONP的最高search结果。 它说:

JSONP或“JSON with padding”是JSON扩展,其中前缀被指定为调用本身的input参数。

咦? 什么叫? 这对我来说没有任何意义。 JSON是一种数据格式。 没有电话。

第二个search结果来自一个名叫Remy的人 ,他写了关于JSONP的文章:

JSONP是脚本标记注入,将来自服务器的响应传递给用户指定的函数。

我可以理解,但它仍然没有任何意义。


那么什么是JSONP? 它为什么创build(它解决了什么问题)? 我为什么要用它?


附录 :我刚在Wikipedia 上为JSONP创build了一个新页面, 它现在有一个清晰和详细的JSONP的描述,根据jvenema的答案。

其实不太复杂

假设你在域example.com上,并且你想向域example.net发出请求。 要做到这一点,你需要跨越领域的界限,在大多数浏览器领域都是不允许的。

绕过这个限制的一个条目是<script>标签。 当您使用脚本标记时,域限制将被忽略,但是在正常情况下,您无法对结果进行任何操作,只会对脚本进行评估。

inputJSONP。 当您向启用了JSONP的服务器发出请求时,会传递一个特殊参数,告诉服务器关于您的页面的一些信息。 这样,服务器就可以很好地包装其响应的方式,您的网页可以处理。

例如,假设服务器需要一个名为“callback”的参数来启用它的JSONPfunction。 那么你的请求将如下所示:

http://www.example.net/sample.aspx?callback=mycallback 

没有JSONP,这可能会返回一些基本的JavaScript对象,如下所示:

 { foo: 'bar' } 

但是,使用JSONP时,当服务器收到“callback”参数时,它将结果稍微不同地包装起来,返回如下所示:

 mycallback({ foo: 'bar' }); 

正如你所看到的,它现在将调用你指定的方法。 所以,在你的页面中,你定义了callback函数:

 mycallback = function(data){ alert(data.foo); }; 

而现在,当脚本被加载时,它将被评估,并且你的函数将被执行。 瞧,跨域请求!

同样值得注意的是JSONP的一个主要问题:您失去了对请求的很多控制。 例如,没有“好”的方法来获得适当的失败代码。 结果,你最终使用定时器来监视请求等,这总是有点怀疑。 JSONRequest的build议是允许跨域脚本,维护安全性并允许正确控制请求的一个很好的解决scheme。

现在(2015年), CORS是推荐的方法与JSONRequest。 JSONP对于较老的浏览器支持仍然有用,但是考虑到安全性,除非你没有select,否则CORS是更好的select。

JSONP实际上是一个简单的技巧来克服XMLHttpRequest相同的域策略。 (正如您所知,不能将AJAX(XMLHttpRequest)请求发送到不同的域。)

因此,我们不必使用XMLHttpRequest,而是使用脚本 HTML标签,通常用来加载js文件,以便js从另一个域中获取数据。 听起来很奇怪?

事情是 – 原来的脚本标签可以以类似于XMLHttpRequest的方式使用! 看一下这个:

 script = document.createElement('script'); script.type = 'text/javascript'; script.src = 'http://www.someWebApiServer.com/some-data'; 

加载数据后,您将看到一个如下所示的脚本段:

 <script> {['some string 1', 'some data', 'whatever data']} </script> 

然而,这有点不方便,因为我们必须从脚本标记中获取这个数组。 所以JSONP的创造者决定,这将工作得更好(而且):

 script = document.createElement('script'); script.type = 'text/javascript'; script.src = 'http://www.someWebApiServer.com/some-data ?callback=my_callback '; 

注意那边的my_callback函数? 所以 – 当JSONP服务器收到你的请求,并findcallback参数 – 而不是返回普通的js数组它会返回这个:

 my_callback({['some string 1', 'some data', 'whatever data']}); 

看看利润在哪里:现在我们得到自动callback(my_callback),一旦我们获得数据,就会触发它。
这就是所有关于JSONP的知识 :它是一个callback和脚本标记。

注:这些是JSONP用法的简单示例,这些不是生产就绪脚本。

基本的JavaScript示例(使用JSONP的简单Twitter推送)

 <html> <head> </head> <body> <div id = 'twitterFeed'></div> <script> function myCallback(dataWeGotViaJsonp){ var text = ''; var len = dataWeGotViaJsonp.length; for(var i=0;i<len;i++){ twitterEntry = dataWeGotViaJsonp[i]; text += '<p><img src = "' + twitterEntry.user.profile_image_url_https +'"/>' + twitterEntry['text'] + '</p>' } document.getElementById('twitterFeed').innerHTML = text; } </script> <script type="text/javascript" src="http://twitter.com/status/user_timeline/padraicb.json?count=10&callback=myCallback"></script> </body> </html> 

基本的jQuery示例(使用JSONP的简单Twitter推送)

 <html> <head> <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script> <script> $(document).ready(function(){ $.ajax({ url: 'http://twitter.com/status/user_timeline/padraicb.json?count=10', dataType: 'jsonp', success: function(dataWeGotViaJsonp){ var text = ''; var len = dataWeGotViaJsonp.length; for(var i=0;i<len;i++){ twitterEntry = dataWeGotViaJsonp[i]; text += '<p><img src = "' + twitterEntry.user.profile_image_url_https +'"/>' + twitterEntry['text'] + '</p>' } $('#twitterFeed').html(text); } }); }) </script> </head> <body> <div id = 'twitterFeed'></div> </body> </html> 

JSONP代表带有填充的JSON 。 (这个技巧很差,因为它与大多数人认为的“填充”无关。)

因为您可以要求服务器为返回的JSON对象附加一个前缀。 例如

function_prefix(json_object);

以便浏览器将JSONstring作为expression式进行“内联” eval 。 这个技巧使得服务器可以直接在客户端浏览器中“注入”JavaScript代码,而绕过“同源”限制。

换句话说,你可以有跨域的数据交换


通常情况下, XMLHttpRequest不允许直接跨域数据交换(需要通过同一个域中的服务器):

<script src="some_other_domain/some_data.js&prefix=function_prefix >”可以访问来自不同于源的域的数据。


另外值得注意的是,即使在尝试这种“诡计”之前服务器应该被视为“可信”,也可以包含对象格式等可能变化的副作用。 如果使用function_prefix (即一个合适的js函数)来接收JSON对象,那么在接受/进一步处理返回的数据之前,所述函数可以执行检查。

JSONP的工作原理是通过构build一个“script”元素(在HTML标记中或通过JavaScript插入到DOM中)来请求远程数据服务位置。 响应是一个JavaScript加载到您的浏览器与预定义函数的名称一起传递的参数,这是请求的JSON数据。 当脚本执行时,该函数与JSON数据一起被调用,允许请求页面接收和处理数据。

进一步阅读访问: https //blogs.sap.com/2013/07/15/secret-behind-jsonp/

客户端代码片段

  <!DOCTYPE html> <html lang="en"> <head> <title>AvLabz - CORS : The Secrets Behind JSONP </title> <meta charset="UTF-8" /> </head> <body> <input type="text" id="username" placeholder="Enter Your Name"/> <button type="submit" onclick="sendRequest()"> Send Request to Server </button> <script> "use strict"; //Construct the script tag at Runtime function requestServerCall(url) { var head = document.head; var script = document.createElement("script"); script.setAttribute("src", url); head.appendChild(script); head.removeChild(script); } //Predefined callback function function jsonpCallback(data) { alert(data.message); // Response data from the server } //Reference to the input field var username = document.getElementById("username"); //Send Request to Server function sendRequest() { // Edit with your Web Service URL requestServerCall("http://localhost/PHP_Series/CORS/myService.php?callback=jsonpCallback&message="+username.value+""); } </script> </body> </html> 

服务器端的一段PHP代码

 <?php header("Content-Type: application/javascript"); $callback = $_GET["callback"]; $message = $_GET["message"]." you got a response from server yipeee!!!"; $jsonResponse = "{\"message\":\"" . $message . "\"}"; echo $callback . "(" . $jsonResponse . ")"; ?> 

JSONP是一个很好的解决跨域脚本错误。 您可以纯粹使用JS来使用JSONP服务,而无需在服务器端实现AJAX代理。

您可以使用b1t.co服务来查看它是如何工作的。 这是一个免费的JSONP服务,使您可以缩小您的URL。 这里是服务使用的url:

http://b1t.co/Site/api/External/MakeUrlWithGet?callback=%5BresultsCallBack%5D&url=%5BescapedUrlToMinify%5D

例如,通话,请http://b1t.co/Site/api/External/MakeUrlWithGet?callback=whateverJavascriptName&url=google.com

会返回

 whateverJavascriptName({"success":true,"url":"http://google.com","shortUrl":"http://b1t.co/54"}); 

因此,当你的js作为一个src加载时,它会自动运行你应该实现的任何javascriptName作为你的callback函数:

 function minifyResultsCallBack(data) { document.getElementById("results").innerHTML = JSON.stringify(data); } 

要实际进行JSONP调用,可以通过几种方法(包括使用jQuery)来完成,但这里是一个纯JS例子:

 function minify(urlToMinify) { url = escape(urlToMinify); var s = document.createElement('script'); s.id = 'dynScript'; s.type='text/javascript'; s.src = "http://b1t.co/Site/api/External/MakeUrlWithGet?callback=resultsCallBack&url=" + url; document.getElementsByTagName('head')[0].appendChild(s); } 

一步一步的例子和一个jsonpnetworking服务练习可在这里: 这个职位

一个使用JSONP的简单例子。

client.html

  <html> <head> </head> body> <input type="button" id="001" onclick=gO("getCompany") value="Company" /> <input type="button" id="002" onclick=gO("getPosition") value="Position"/> <h3> <div id="101"> </div> </h3> <script type="text/javascript"> var elem=document.getElementById("101"); function gO(callback){ script = document.createElement('script'); script.type = 'text/javascript'; script.src = 'http://localhost/test/server.php?callback='+callback; elem.appendChild(script); elem.removeChild(script); } function getCompany(data){ var message="The company you work for is "+data.company +"<img src='"+data.image+"'/ >"; elem.innerHTML=message; } function getPosition(data){ var message="The position you are offered is "+data.position; elem.innerHTML=message; } </script> </body> </html> 

server.php

  <?php $callback=$_GET["callback"]; echo $callback; if($callback=='getCompany') $response="({\"company\":\"Google\",\"image\":\"xyz.jpg\"})"; else $response="({\"position\":\"Development Intern\"})"; echo $response; ?> 

在理解JSONP之前,您需要知道JSON格式和XML。 目前Web上最常用的数据格式是XML,但XML非常复杂。 这使用户不便处理embedded在网页中。

为了使JavaScript能够轻松地交换数据,即使是作为数据处理程序,我们也根据JavaScript对象的措辞,开发了一种简单的数据交换格式,即JSON。 JSON可以用作数据,或者用作JavaScript程序。

JSON可以直接embedded到JavaScript中,使用它们可以直接执行某些JSON程序,但是由于安全约束,浏览器Sandbox机制禁止了跨域JSON代码的执行。

为了使JSON可以在执行后传递,我们开发了一个JSONP。 JSONP使用JavaScriptcallback函数和<script>标记绕过浏览器的安全限制。

总之,它解释了什么是JSONP,它解决了什么问题(何时使用它)。