Ajax Callback函数的位置

时间:2016-06-09 15:36:05

标签: javascript jquery ajax

我遇到了一个位于$(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 :对不起,伙伴们,链接并不相同。我忘了改变第二个。读取功能的位置只有一个区别。

4 个答案:

答案 0 :(得分:4)

将JsonP回调名称作为字符串传递的原因是因为JQuery需要将其添加到您的URL ?callback=read。 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 Demo:http://codepen.io/anon/pen/qNbRQw

如果您想进一步了解JsonP的工作原理,请继续阅读。

如果您仍然感到困惑,可能是因为您并不是100%熟悉JsonP的实际工作方式。 JsonP是一个可以绕过Same-origin Policy的黑客。同源策略的简短版本是浏览器不会让您读取从请求发出的域以外的域请求返回的响应,除非该域名的服务器说它没关系

大多数浏览器都实施了同源策略,以帮助保护用户免受恶意脚本的攻击。例如,如果您在一个浏览器选项卡中使用您的银行网站进行了身份验证,然后在另一个选项卡中访问了一个恶意网站,则浏览器中没有相同来源的限制,恶意网站可能会向您的银行网站发出ajax请求。该请求将携带您的浏览器为该域存储的任何cookie,并且您的cookie将向您显示经过身份验证的cookie,从而使攻击脚本可以访问您的银行帐户中的经过身份验证的数据。同源策略可防止恶意网站查看该请求的响应数据。

一开始,客户端和服务器没有正式的方式选择加入跨域共享。它当时被浏览器直接阻止了。为了解决这个问题,JsonP被发明了。同源策略仅隐藏来自ajax请求的响应,但您可能已经注意到浏览器完全可以通过<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加载脚本并执行它。该脚本正被加载到页面的全局范围中,因此在调用read函数时,它希望该函数也存在于全局范围内。

今天,围绕同源政策的官方方式是通过跨源资源共享政策(又名CORS)。 JsonP基本上完成了与正确的CORS请求相同的事情。服务器必须通过知道如何将响应格式化为可执行JavaScript来选择加入,并且客户端必须知道不执行正常的ajax请求,而是动态创建脚本标记并将其嵌入到页面主体中。然而,JsonP仍然是一个黑客攻击,而且随着黑客攻击,它会带来一系列的缺点。 JsonP真的很难调试,因为处理错误几乎是不可能的。如果请求失败,则没有简单的方法来捕获错误,因为请求是通过<script>标记进行的。 <script>标记也无法控制正在进行的请求的格式;它只能发出简单的GET请求。 JsonP的最大缺点是需要创建一个全局函数来用作数据的回调。没有人喜欢污染全局命名空间,但是JsonP无需工作。

正确的CORS请求不需要客户额外的努力。浏览器知道如何询问服务器是否允许读取数据。服务器只需要使用正确的CORS标头回复说它没关系,然后浏览器将解除相同的来源限制,并允许您像该域一样正常使用ajax。但有时候你试图点击的资源只知道JsonP并且没有返回正确的CORS标题,因此你必须回退它。

关于CORS的更多信息我不久前写了一篇非常详细的blog post,这应该真的有助于你理解它。如果您控制的服务器返回您之后的数据,那么您应该考虑让它返回正确的CORS标头并忘记JsonP。但是,当您不控制服务器并且无法将其配置为返回正确的标头时,它完全可以理解。有时JsonP是获得所需内容的唯一方法,即使它确实会让你在编写代码时呕吐一点。

希望有助于为您解决一些问题:)

答案 1 :(得分:0)

$(document).ready(function() {表示:在页面加载完成后执行此操作。 在第二个示例中,仅在页面加载完成后才定义read函数。

在工作示例中,您首先定义read函数并说,&#34;加载页面后,执行ajax调用,然后调用read函数&#34;

编辑:另外,您可以阅读@IGeoorge答案以获得更详细的解释。

答案 2 :(得分:-1)

在ajax之前添加read方法

$(document).ready(function() {
  var read = function(data) {
    console.log(data);
  }
  $("#ara-button").click(function() {
    $.ajax({
      url: "http://www.csstr.com/data.json",
      type: "get",
      dataType: "jsonp",
      jsonpCallback: "read",
    });
  });

});

答案 3 :(得分:-1)

你的函数被定义为Jquery Scope,所以在执行ajax的那一刻,找不到&#34; read&#34;的定义。功能

这就是第一个例子有效的原因。

希望这有帮助。