What is JSONP, and why was it created?
我了解JSON,但不了解JSONP。维基百科关于JSON的文档是JSONP的最热门搜索结果。它说:
JSONP or"JSON with padding" is a JSON extension wherein a prefix is specified as an input argument of the call itself.
呵呵?叫什么?这对我来说毫无意义。JSON是一种数据格式。没有电话。
第二个搜索结果来自一个叫Remy的人,他写了关于jsonp的文章:
JSONP is script tag injection, passing the response from the server in to a user specified function.
我可以理解,但这仍然没有任何意义。
那么什么是jsonp?为什么要创建它(它解决了什么问题)?我为什么要用它?
附录:我刚刚在维基百科上为jsonp创建了一个新页面;现在它根据jvenema的答案对jsonp进行了清晰而全面的描述。
- 斯卡夫曼,那么,从你低下头的语气来看,你是那个从维基百科中删除了最合理问题的人吗?没有添加任何东西或改进它?问一个问题是"破坏公物"吗?谢斯。是的,在这一刻,我将改进维基百科的页面,利用jvenema提供的信息。
- 作为记录,如果您不信任与之交谈的服务器,就不要使用JSONP。如果它被泄露了,你的网页将受到轻微的泄露。
- 另外请注意,如果没有正确实现JSONP,它可能被劫持。
- 我想赞扬JSONP的作者,他提出了JSONP背后的哲学:BobIpolito的JSONP档案。他将JSONP介绍为"跨域数据获取的脚本标记方法的一种新技术不可知的标准方法"。
- 为什么这个问题被标记为复制品,而这个问题的"复制品"是在这个问题10个月后被问到的?
其实并不太复杂…
假设你在域example.com上,你想向域example.net发出请求。要做到这一点,你需要跨越领域边界,在大多数浏览器领域都是不允许的。
绕过这个限制的一个项目是标签。当您使用脚本标记时,域限制被忽略,但是在正常情况下,您不能对结果做任何实际操作,脚本只会得到评估。
输入JSONP。当您向启用了JSONP的服务器发出请求时,您将传递一个特殊的参数,该参数告诉服务器一些关于您的页面的信息。这样,服务器就能够以页面可以处理的方式很好地总结其响应。
例如,假设服务器需要一个名为"callback"的参数来启用其JSONP功能。那么您的请求如下:
1
| http://www.example.net/sample.aspx?callback=mycallback |
如果没有jsonp,这可能会返回一些基本的javascript对象,如:
但是,对于jsonp,当服务器接收到"callback"参数时,它对结果进行了稍微不同的包装,返回如下内容:
1
| mycallback({ foo: 'bar' }); |
如您所见,它现在将调用您指定的方法。因此,在您的页面中,您定义回调函数:
1 2 3
| mycallback = function(data){
alert(data.foo);
}; |
现在,当加载脚本时,将对其进行评估,并执行函数。瞧,跨域请求!
同样值得注意的是,JSONP的一个主要问题是:您失去了对请求的大量控制。例如,没有"好"的方法来获取正确的故障代码。结果,您最终使用计时器来监视请求等,这总是有点可疑。JSONREQUEST的提议是一个很好的解决方案,它允许跨域脚本、维护安全性,并允许对请求进行适当的控制。
这些天(2015年),CORS是推荐的方法,而不是JSONREQUEST。JSONP对于旧的浏览器支持仍然有用,但是考虑到安全性的影响,除非您没有选择,否则CORS是更好的选择。
- 请注意,使用JSONP会带来一些安全隐患。因为JSONP实际上是一个JavaScript,它可以做JavaScript所能做的一切,所以您需要信任JSONP数据的提供者。我在这里写了一篇关于它的博客文章:erlend.ofthedal.no/blog/?BLUGID=97
- JSONP中是否确实存在标记中不存在的任何新的安全含义?通过脚本标记,浏览器隐式地信任服务器提供无害的javascript,浏览器盲目地评估它。JSONP是否改变了这一事实?似乎不是。
- 不,它不是。如果你相信它可以提供JavaScript,同样的事情也适用于JSONP。
- 值得注意的是,通过更改数据的返回方式,可以稍微提高安全性。如果以真正的JSON格式返回脚本,如mycallback(""foo":"bar"")(请注意,参数现在是一个字符串),则可以在评估之前手动将数据解析为"清理"。
- @奇索:不,问题完全一样。但有些人没有意识到这是个问题。@jvenema:您仍然需要信任数据的提供者:-)
- @Erlend,没有意见分歧-任何时候当你加载跨域的东西时,你至少要对你正在加载的东西有一些信任:)
- @jvenema curl还为跨域数据检索(afaik)开发,那么jsonp的需求是什么?
- curl是服务器端解决方案,而不是客户端。它们有两个不同的用途。
- foo:'bar'作为JS对象文本是完全合法的,这就是我的示例所示-JSONP可以很好地处理对象文本或严格的JSON。
- @Stephen { 'foo' : 'bar' }仍然不是有效的JSON。需要双引号。
- @Cheeso-不同之处在于,标签通常指的是您自己控制的资源。例如,如果您不信任cdn,只需将脚本复制到您自己的服务器。如果您希望数据从不直接控制的服务器传输到网页,那么JSONP不可能使用该选项。不过,JVenema的解决方案是个好主意。
- @昆廷-一些好的想法在你的编辑,但他们改变了一些简单和明确的原始答案。我添加了一个引用CORS作为选项的编辑。
- 我认为jsonrequest是一个红鲱鱼,据我所知,没有任何浏览器支持它。
- 将所有非JSONP示例作为JavaScript的片段而不是JSON也很奇怪,因为人们通常已经在使用JSON了(尤其是在考虑JSONP的时候)。
- 想想看,您的JSONP示例甚至不是JSONP。它只是javascript,但函数参数是无效的JSON。它在大多数情况下都可以工作,但不适用于偶尔的JSONP解析器,它去掉回调的内容,然后将其余的内容传递给JSON解析器。
- 那么,callback=?意味着我们在服务器上分配包装名称,对吗?我以为我们在传递一个唯一的标识符来确定页面实例或其他东西,但这更有意义。伟大的职位!
- 对的。由于JS在收到响应后立即由浏览器执行,因此您必须告诉服务器(在浏览器中)您想要调用什么函数,并且服务器负责包装数据,以便它调用该函数。
- @Quentin-请参见线程开头的注释re:json vs js文本。
- 所以基本上你可以不知道它是如何工作的就继续前进?…
- 值得指出的是,返回的脚本不允许与DOM混淆。这就是为什么你要传递你自己的函数名,你要引用它。
- @jsonp通过在页面中注入脚本来工作。返回的脚本可以随意处理DOM。JSONP为您打开了来自数据源的XSS攻击,因此您必须完全信任数据源。(这就是为什么CORS更好,它不受这个问题的影响)。
- @好吧-不太好。callback=?表示包装名称由客户端库决定,客户端库将用随机的东西替换?以避免冲突(因为被调用的函数必须是全局的)。然后,服务器将使用生成回调时替换为?的函数名。
- @昆廷,谢谢。因此,我们可以有效地说,您提供的回调为数据源开发人员打开了安全门。
- @胆囊炎是的!因此,人们对安全问题的评论众说纷纭
- 昆廷通过函数参数注入Java脚本是多么危险,这不是仅限于数据而不是可执行JS吗?
- @ CholthiPaulTtiopic——"通过函数参数注入Java脚本是多么危险"——它将充分暴露给站点想要发送的任何JS。这不仅限于数据,而且不限于可执行JS吗?-不,它不限于。您可以在函数参数中放入任何您喜欢的表达式。alert( function() { do_bad_stuff(); return"xss" }() );。即使事实并非如此,您也在从第三方加载脚本。他们不必向您发送一个符合JSONP惯例的消息。不用提你的回拨。它可能只是一个简单的攻击脚本。
- @昆汀哇!JSONP库是否只是在确保数据源提供有效回调之前将所有内容都回送到脚本标记中?这将是一个普通的跨域请求。
- @不,为了做到这一点,它必须能够使用xhr以纯文本的形式读取脚本。JSONP的关键是要绕过这个问题。客户端库(1)注入一个随机名称的函数,例如您的_回调(2)注入
JSONP通过构造"script"元素(在HTML标记中或通过javascript插入到DOM中)来工作,该元素请求远程数据服务位置。响应是加载到浏览器上的一个javascript,带有预定义函数的名称,以及所请求的JSON数据所传递的参数。当脚本执行时,函数与JSON数据一起调用,允许请求页面接收和处理数据。
欲了解更多信息,请访问:https://blogs.sap.com/2013/07/15/secret-behind-jsonp/
客户端代码段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| <!DOCTYPE html>
<html lang="en">
<head>
AvLabz - CORS : The Secrets Behind JSONP
<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>
"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+"");
}
</body>
</html> |
服务器端的一段PHP代码
1 2 3 4 5 6 7
| <?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 .")";
?> |
- 上面的链接现在才404
- 该链接的内容现在可以在http://scn.sap.com/community/developer center/front-end/blog&zwnj;&8203;/2013/07/15/secret-b&zwnj;&8203;ehind jsonp上找到。
因为您可以要求服务器向返回的JSON对象追加前缀。例如
function_prefix(json_object);
为了让浏览器"内联"eval的JSON字符串作为表达式。这一技巧使得服务器可以直接在客户机浏览器中"注入"javascript代码,并且可以绕过"同一来源"的限制。
换句话说,您可以进行跨域数据交换。
通常,XMLHttpRequest不允许直接进行跨域数据交换(需要通过同一域中的服务器),但是:
在理解JSONP之前,您需要了解JSON格式和XML。目前Web上最常用的数据格式是XML,但是XML非常复杂。这使得用户不方便处理嵌入在网页中的内容。
为了使javascript能够很容易地交换数据,甚至作为数据处理程序,我们根据javascript对象使用了这个词,并开发了一种简单的数据交换格式,即JSON。JSON可以用作数据,也可以用作JavaScript程序。
JSON可以直接嵌入到JavaScript中,使用它们可以直接执行某些JSON程序,但由于安全限制,浏览器沙盒机制禁用跨域JSON代码执行。
为了使JSON在执行之后能够被传递,我们开发了一个JSONP。jsonp通过javascript回调功能和