什么是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=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,它解决了什么问题(何时使用它)。