【发布时间】:2011-04-19 21:23:54
【问题描述】:
我知道JSONP 是带有填充的JSON。
我了解 JSON 是什么,以及如何将它与 jQuery.getJSON() 一起使用。但是,在介绍 JSONP 时,我不明白callback 的概念。
谁能向我解释一下这是如何工作的?
【问题讨论】:
我知道JSONP 是带有填充的JSON。
我了解 JSON 是什么,以及如何将它与 jQuery.getJSON() 一起使用。但是,在介绍 JSONP 时,我不明白callback 的概念。
谁能向我解释一下这是如何工作的?
【问题讨论】:
假设您有一些 URL 为您提供 JSON 数据,例如:
{'field': 'value'}
...你有一个类似的 URL,除了它使用 JSONP,你将回调函数名称“myCallback”传递给它(通常通过给它一个名为“callback”的查询参数来完成,例如http://example.com/dataSource?callback=myCallback)。然后它会返回:
myCallback({'field':'value'})
...这不仅仅是一个对象,而是实际上可以执行的代码。因此,如果您在页面的其他位置定义了一个名为 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
}
});
这里,jQuery 负责回调函数名称和查询参数 - 使 API 与其他 ajax 调用相同。但与其他类型的 ajax 请求不同,如前所述,您不限于从与您的页面相同的来源获取数据。
【讨论】:
这个答案已经超过六年了。虽然 JSONP 的概念和应用没有改变 (即答案的细节仍然有效),你应该 look to use CORS where possible (即您的server 或 API 支持它,并且 browser support 就足够了), 作为 JSONP has inherent security risks。
JSONP(JSON with Padding)是一种常用的方法 绕过浏览器中的跨域策略。 (您不得向浏览器认为位于不同服务器上的网页发出 AJAX 请求。)
JSON 和 JSONP 在客户端和服务器上的行为不同。 JSONP 请求不使用XMLHTTPRequest 和相关的浏览器方法分派。而是创建了一个 <script> 标记,其源设置为目标 URL。然后将此脚本标记添加到 DOM(通常在 <head> 元素内)。
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
// success
};
};
xhr.open("GET", "somewhere.php", true);
xhr.send();
var tag = document.createElement("script");
tag.src = 'somewhere_else.php?callback=foo';
document.getElementsByTagName("head")[0].appendChild(tag);
JSON 响应和 JSONP 响应的区别在于 JSONP 响应对象作为参数传递给回调函数。
{ "bar": "baz" }
foo( { "bar": "baz" } );
这就是为什么您会看到 JSONP 请求包含 callback 参数,以便服务器知道包装响应的函数的名称。
此函数必须存在在全局范围内当时浏览器评估<script>标签(一旦请求完成)。
在处理 JSON 响应和 JSONP 响应之间需要注意的另一个区别是,JSON 响应中的任何解析错误都可以通过包装评估 responseText 的尝试来捕获 在 try/catch 语句中。由于 JSONP 响应的性质,响应中的解析错误将导致无法捕获的 JavaScript 解析错误。
两种格式都可以通过在发起请求之前设置超时并在响应处理程序中清除超时来实现超时错误。
使用jQuery 发出 JSONP 请求的用处在于 jQuery 在后台为您完成所有工作。
默认情况下,jQuery 要求您在 AJAX 请求的 URL 中包含 &callback=?。 jQuery 将获取您指定的success 函数,为其分配一个唯一的名称,并在全局范围内发布它。然后它将用它分配的名称替换&callback=? 中的问号?。
以下假设一个响应对象{ "bar" : "baz" }
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();
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);
【讨论】:
JSON.parse 替换为eval 以获取安全性还有很长的路要走。
XMLHttpRequest 之外有支持(注意这个答案来自 2010 年!)。鉴于 Microsoft 不再支持这些浏览器,并且 JSONP 的安全隐患,应尽可能使用 CORS(如果可用)。
JSONP 是一种绕过浏览器same-origin policy 的方法。如何?像这样:
这里的目标是向响应中的名称otherdomain.com 和alert 发出请求。通常我们会发出 AJAX 请求:
$.get('otherdomain.com', function (response) {
var name = response.name;
alert(name);
});
但是,由于请求将发送到不同的域,所以它不起作用。
不过,我们可以使用<script> 标签发出请求。 <script src="otherdomain.com"></script> 和 $.get('otherdomain.com') 都会产生相同的请求:
GET otherdomain.com
问:但是如果我们使用<script> 标签,我们如何访问响应?如果我们想alert它,我们需要访问它。
A:呃,我们不能。但我们可以这样做 - 定义一个使用响应的函数,然后告诉服务器使用 JavaScript 响应,该 JavaScript 以响应作为参数调用我们的函数。
问:但是如果服务器不为我们做这件事,而只愿意返回 JSON 给我们呢?
A:那我们就不能用了。 JSONP需要服务器配合。
问:必须使用<script> 标签很难看。
答:像 jQuery make it nicer 这样的库。例如:
$.ajax({
url: "http://otherdomain.com",
jsonp: "callback",
dataType: "jsonp",
success: function( response ) {
console.log( response );
}
});
它通过动态创建 <script> 标签 DOM 元素来工作。
问:<script> 标签只发出 GET 请求 - 如果我们想发出 POST 请求怎么办?
A:那么 JSONP 对我们不起作用。
问:没关系,我只想发出一个 GET 请求。 JSONP 很棒,我会去使用它 - 谢谢!
A:实际上,它并没有那么棒。这真的只是一个黑客。和它isn't the safest 使用的东西。现在 CORS 可用,您应该尽可能使用它。
【讨论】:
我找到了一篇有用的文章,该文章也非常清楚和简单地解释了该主题。链接是JSONP
一些值得注意的点是:
工作如下:
<script src="url?callback=function_name"> 包含在 html 代码中【讨论】: