任何人都可以用通俗的话来解释JSONP是什么?
我知道JSONP
是带填充的JSON
。
我了解JSON是什么,以及如何使用jQuery.getJSON()
。 但是,我不明白引入JSONP时的callback
的概念。
任何人都可以向我解释这是如何工作的?
前言:
这个答案已经六年多了。 尽pipeJSONP的概念和应用没有改变(即答案的细节仍然有效),但是您应该尽可能使用CORS (即您的服务器或API支持它,并且浏览器支持是足够的),因为JSONP 有固有的安全风险 。
JSONP( 带填充的JSON )是一种通常用于绕过Web浏览器中的跨域策略的方法。 (您不允许通过浏览器向被认为位于不同服务器上的网页发出AJAX请求。)
JSON和JSONP在客户端和服务器上的行为不同。 JSONP请求不使用XMLHTTPRequest
和相关的浏览器方法分派。 而是创build一个<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响应对象作为parameter passing给callback函数。
JSON:
{ "bar": "baz" }
JSONP:
foo( { "bar": "baz" } );
这就是为什么您会看到包含callback
参数的JSONP请求,以便服务器知道函数的名称以包装响应。
在浏览器评估<script>
标签时 ,该函数必须存在于全局范围内(一旦请求完成)。
在处理JSON响应和JSONP响应之间需要注意的另一个区别是,通过在try / catch语句中包装尝试评估responseText,可以捕获JSON响应中的任何parsing错误。 由于JSONP响应的本质,响应中的parsing错误将导致不可parsing的JavaScriptparsing错误。
这两种格式都可以通过在启动请求之前设置超时并在响应处理程序中清除超时来实现超时错误。
使用jQuery来创buildJSONP请求的用处是,jQuery在后台为您完成所有工作 。
jQuery默认要求你包含&callback=?
在你的AJAX请求的URL中。 jQuery将采用您指定的success
函数,为其分配一个唯一的名称,并将其发布到全局范围中。 它会取代问号?
in &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);
假设你有一些URL给了你JSON数据,如:
{'field': 'value'}
…除了使用JSONP之外,您还有一个类似的URL,您向其传递了callback函数名称“myCallback”(通常通过为其提供一个名为“callback”的查询参数,例如http://example.com/dataSource?callback=myCallback
)。 然后它会返回:
myCallback({'field':'value'})
…这不仅仅是一个对象,而是实际上可以执行的代码。 因此,如果您在页面的其他地方定义了一个名为myFunction
的函数并执行该脚本,则将使用URL中的数据调用该函数。
这很酷的事情是:你可以创build一个脚本标签,并使用你的URL(完整的callback
参数)作为src
属性,浏览器将运行它。 这意味着您可以绕过“同源”安全策略(因为浏览器允许您从页面域以外的来源运行脚本标记)。
这是jQuery在做一个ajax请求时所做的(使用带'jsonp'的.ajax
作为dataType
属性的值)。 例如
$.ajax({ url: 'http://example.com/datasource', dataType: 'jsonp', success: function(data) { // your code to handle data here } });
在这里,jQuery负责callback函数名称和查询参数 – 使API与其他Ajax调用相同。 但是,与其他types的Ajax请求不同,如上所述,您并不局限于从页面的相同来源获取数据。
JSONP是一种避开浏览器的同源策略的方式 。 怎么样? 喜欢这个:
这里的目标是向otherdomain.com
发出请求,并在响应中alert
名称。 通常我们会发出一个AJAX请求:
$.get('otherdomain.com', function (response) { var name = response.name; alert(name); });
但是,由于请求正在进入不同的域,因此不起作用。
尽pipe我们可以使用<script>
标签来发送请求。 <script src="otherdomain.com"></script>
和$.get('otherdomain.com')
都会导致相同的请求:
GET otherdomain.com
问:但是,如果我们使用<script>
标签,我们如何访问响应? 如果我们要alert
它,我们需要访问它。
A:呃,我们不能。 但是,我们可以这样做 – 定义一个使用响应的函数,然后告诉服务器用JavaScript进行响应,以响应作为参数调用我们的函数。
问:但是,如果服务器不会为我们做这件事,而只是愿意把JSON还给我们呢?
A:那我们将无法使用它。 JSONP要求服务器合作。
问:不得不使用<script>
标签是丑陋的。
答:像jQuery 这样的库使它更好 。 例如:
$.ajax({ url: "http://otherdomain.com", jsonp: "callback", dataType: "jsonp", success: function( response ) { console.log( response ); } });
它通过dynamic创build<script>
标记DOM元素来工作。
问: <script>
标签只会产生GET请求 – 如果我们想发出POST请求呢?
答:那么JSONP不会为我们工作。
问:没关系,我只是想做一个GET请求。 JSONP是真棒,我要去用它 – 谢谢!
A:其实并不是那么棒。 这真的只是一个黑客。 这不是最安全的使用。 现在CORS是可用的,你应该尽可能使用它。
我find了一篇很有用的文章,也很清楚和简单的语言解释了这个话题。 链接是JSONP
一些值得注意的地方是:
- JSONP在CORS之前的date。
- 这是从不同领域获取数据的伪标准方式,
- 它具有有限的CORS特性(只有GET方法)
工作如下:
-
<script src="url?callback=function_name">
包含在html代码中 - 当第一步得到执行时,它会传递一个具有相同函数名称的函数(如url参数中给出的)作为响应。
- 如果具有给定名称的函数存在于代码中,它将与数据(如果有)一起作为参数返回给该函数。