我对位于$(document).ready
中的回调函数有问题。回调功能过去不起作用。当我将其放在$(document).ready
之外时,代码已开始正常工作。我不明白为什么。位置重要吗?
这有效:
$(document).ready(function() {
$("#button1").click(function() {
$.ajax({
url: "http://www.example.com/data.php",
type: "get",
dataType: "jsonp",
jsonpCallback: "read",
});
});
});
var read = function(data) {
console.log(data);
}
这是行不通的。
$(document).ready(function() {
$("#button1").click(function() {
$.ajax({
url: "http://www.example.com/data.php",
type: "get",
dataType: "jsonp",
jsonpCallback: "read",
});
});
var read = function(data) {
console.log(data);
}
});
UPDATE1:抱歉,链接没有什么不同。我忘了换第二个。读取功能的位置只有一个区别。
最佳答案
之所以将JsonP回调名称作为这样的字符串传递,是因为JQuery需要像?callback=read
这样将其添加到您的URL中。 JsonP请求只是由JQuery在后台创建并添加到页面<script>
的<script src="http://www.csstr.com/data.json?callback=read"></script>
标记。一旦JQuery将该脚本标签添加到您的页面,浏览器就会将其视为加载要执行的常规JavaScript文档。由于请求的?callback=read
部分,远程服务器知道使用可执行的JavaScript进行响应,而不仅仅是原始数据。该可执行JavaScript只是对具有您提供的名称的函数的函数调用,在本例中为read
函数。由于返回的脚本是在全局范围内执行的,因此read
函数也需要在全局范围内存在。浏览器中的全局作用域是window
对象,因此,基本上read
函数需要出现在window
对象上,以便执行的脚本找到该函数。
$(document).ready(function() {
$("#ara-button").click(function() {
$.ajax({
url: "http://www.csstr.com/data.json",
type: "get",
dataType: "jsonp",
jsonpCallback: "read",
});
});
window.read = function(data) {
console.log(data);
}
});
在第一个示例中,它在ready函数之外起作用,因为在根级别定义的所有内容都是全局范围的。
Codpen演示:http://codepen.io/anon/pen/qNbRQw
如果您想进一步了解JsonP的工作原理,请继续阅读。
如果您仍然感到困惑,那可能是因为您不是100%熟悉JsonP的实际工作方式。 JsonP是绕过Same-origin Policy的一种技巧。同源策略的简短版本是,浏览器将不允许您将请求返回的响应读取到请求源以外的域,除非该其他域上的服务器认为可以。
大多数浏览器都实施了同源策略,以帮助保护用户免受恶意脚本的攻击。例如,如果您在一个浏览器选项卡中通过银行网站进行了身份验证,然后在另一个选项卡中转到了一个恶意网站,而浏览器中没有相同来源的限制,那么该恶意网站可能会向您的银行网站提出ajax请求。该请求将携带您的浏览器为该域存储的任何cookie,并且cookie将显示您已通过身份验证,从而使攻击脚本可以访问您银行帐户中经过身份验证的数据。 “同源策略”可防止恶意站点看到该请求的响应数据。
最初,客户端和服务器没有正式的方式选择加入跨域共享。当时它只是被浏览器直接阻止。为了解决这个问题,发明了JsonP。 “同源策略”仅隐藏来自Ajax请求的响应,但是您可能已经注意到,浏览器可以通过
<script>
标记从其他网站加载脚本,这是完全可以的。 script标记只是对javascript文档执行普通的GET请求,然后开始在页面上执行该脚本。 JsonP利用了同源限制不适用于<script>
标签的事实。请注意,如果您直接在浏览器中转到http://www.csstr.com/data.json,您将看到您要查找的数据。但是,尝试添加以下查询字符串到那里。
http://www.csstr.com/data.json?callback=read
注意到有什么不同吗?您不仅希望返回数据,还希望将数据传递到名为
read
的函数中,从而使响应返回。这就是您知道服务器了解JsonP hack的方式。它知道将所需的数据包装在函数调用中,以便JQuery可以在客户端上执行JsonP hack,方法是创建<script>
标记并将其嵌入到您的网页中。该脚本标记指向URL,但也将查询字符串添加到URL的末尾。结果是一个脚本标记,该标记从该URL加载脚本并执行该脚本。该脚本将被加载到页面的全局范围内,因此,当调用read
函数时,它希望该函数也存在于全局范围内。今天,绕过同源策略的官方方法是通过跨域资源共享策略(又名CORS)。 JsonP本质上完成了与正确的CORS请求相同的任务。服务器必须通过知道如何将响应格式化为可执行JavaScript来选择加入,而客户端则必须知道不执行正常的ajax请求,而是动态创建脚本标记并将其嵌入页面主体中。但是,JsonP仍然是一个hack,而且随着hack的发展,它也有自己的缺点。 JsonP确实很难调试,因为几乎不可能处理错误。如果请求失败,则没有简单的方法来捕获错误,因为该请求是通过
<script>
标记发出的。 <script>
标记也无法控制所发出请求的格式;它只能发出简单的GET请求。 JsonP的最大缺点是需要创建一个全局函数用作数据的回调。没有人喜欢污染全局名称空间,但要使JsonP起作用,它是必需的。正确的CORS请求不需要客户方面的额外努力。浏览器知道如何询问服务器是否允许读取数据。服务器只需要用正确的CORS标头回应就可以了,然后浏览器将解除同源限制,并允许您在该域中正常使用ajax。但是有时,您尝试访问的资源仅知道JsonP,而不会返回正确的CORS标头,因此您必须回退它。
有关CORS的更多信息,我前一阵子写了一个非常详细的blog post,它确实可以帮助您理解它。如果您控制返回数据的服务器,则应该考虑让它返回正确的CORS标头,而不必理会JsonP。但是,当您不控制服务器并且无法将其配置为返回正确的标头时,这是完全可以理解的。有时,JsonP是获得所需内容的唯一方法,即使它确实使您在编写代码时有点费劲。
希望能为您解决一些问题:)