jQuery跨域ajax:执行时回调

Posted

技术标签:

【中文标题】jQuery跨域ajax:执行时回调【英文标题】:jQuery cross-domain ajax: callback when executed 【发布时间】:2013-09-17 12:00:03 【问题描述】:

背景

我正在通过 jQuery 的 .ajax(...) 调用从另一台服务器(跨域)加载和执行脚本。

来自其他服务器的代码执行之后需要执行一些代码,否则有些对象是“未定义的”。

也许很重要:远程代码确实包含另一个getScript(...) 调用。我也必须等待这段代码被执行。我不能简单地从我的代码中加载第二个脚本,因为它的源是动态的(即取决于远程脚本的某些结果)。

无效:success 回调

显然,在远程代码加载之后调用了success回调,但是之前远程代码执行

# coffee script

executeLater = ->
  # this bit of code needs to run after the remote code has been executed.
  console.log("yehaa!")

$.getScript("http://example.com/script-from-other-server.js")
.success(executeLater)  # this gets executed when the remote script is loaded,
                        # but before the remote script is executed.

无效:async: false

显然,对于跨域请求,async 属性被忽略,如 jQuery 文档中所述:http://api.jquery.com/jQuery.ajax/#jQuery-ajax-settings

此外,我想避免使用async: false 设置,因为据说它会阻止浏览器。

# coffee script

executeLater = ->
  # this bit of code needs to run after the remote code has been executed.
  console.log("yehaa!")

$.ajax(
  dataType: 'script',
  url: 'http://example.com/script-from-other-server.js',
  async: false   # does not work because the request is cross domain
)
.success(executeLater)

无效:$.when(...).then(...)

显然,使用 jQuery 的 when-then mechanism,then 代码在 when 块 执行 之前执行。

# coffee script

executeLater = ->
  # this bit of code needs to run after the remote code has been executed.
  console.log("yehaa!")

$.when( $.ajax(
  dataType: 'script',
  url: 'http://example.com/script-from-other-server.js',
) ).then(executeLater)

编辑:确实有效,但无法使用:ajax 两个脚本

正如我在上面的“背景”部分所说,我不能在生产环境中执行此操作,但是如果我将所有案例减少到一个并在我自己的脚本中加载通常由远程脚本执行的第二个脚本,一切正常。

# coffee script

executeLater = ->
  # this bit of code needs to run after the remote code has been executed.
  console.log("yehaa!")

$.getScript("http://example.com/script-from-other-server.js")
.success( ->
  $.ajax(
    dataType: 'script',
    cache: true,
    # I do not know this url in production:
    url: 'http://example.com/another-script-from-the-remote-server.js'  
  )
  .success(executeLater)
)

要避免的事情

在定义某个对象并执行executeLater() 方法之前,我不愿意使用像几个setTimout 调用这样的结构。

我需要:executed 回调

最好使用一种executed 回调而不是ajax 方法的success 回调。但是,到目前为止,我还没有找到这个回调。

# coffee script

executeLater = ->
  # this bit of code needs to run after the remote code has been executed.
  console.log("yehaa!")

$.ajax(
  dataType: 'script',
  url: 'http://example.com/script-from-other-server.js',
  executed: executeLater  # <---- I NEED A CALLBACK LIKE THIS
)

有什么线索吗?

有谁知道我如何在远程代码执行后执行executeLater 方法?谢谢!

编辑:同源政策

正如 adeneo 在 cmets 部分指出的那样,javascript 的 same-origin policy 可能是问题所在。

我使用ajaxgetScript 调用加载的脚本不允许从远程服务器加载和执行另一个脚本,以防止恶意脚本“回家”。

以下实验支持这一点:

这不起作用:

<html><head>
  <script language="javascript" src="http://code.jquery.com/jquery-1.10.2.js"></script>
  <script language="javascript">
    jQuery.getScript("http://example.com/script-from-other-server.js")
  </script>
</head><body></body></html>

这行得通:

根据this stackexchange answer,同源策略允许通过html &lt;script&gt;标签加载的远程脚本通过ajax加载其他远程脚本。

<html><head>
  <script language="javascript" src="http://code.jquery.com/jquery-1.10.2.js"></script>
  <script language="javascript" src="http://example.com/script-from-other-server.js"></script>
</head><body></body></html>

问题仍然存在:有没有一种通过 ajax 调用的好方法,或者,我是否必须通过插入 &lt;script&gt; 标签来“证明”我“拥有此代码”在html文档中?

【问题讨论】:

这是一个格式很好的问题,但最大的问题仍然是,你确定 JavaScript 的同源策略不是问题吗? @adeneo :我不确定,我怎样才能知道?我刚刚添加了“确实有效,但无法使用:ajax 两个脚本”部分。这能回答你的问题吗? @adeneo :我看起来你是对的:SOP 可能是问题所在。请查看“编辑:同源政策”部分。你怎么看? 如您所说...您可能必须将脚本添加到您的 dom 元素以克服 SOP 问题...但仍然存在第二个问题...即在动态脚本加载完成 能否对第一个动态脚本元素进行一些更改 【参考方案1】:

背景

adeneo 建议考虑 JavaScripts Same-Origin Policy(请参阅问题的 cmets)确实解决了我的问题。

问题假设在请求的脚本完全执行之前调用了success 回调,真正的问题是,请求的脚本确实请求另一个脚本,如问题中所述:

也许很重要:远程代码确实包含另一个getScript(...) 调用。我也必须等待这段代码被执行。我不能简单地从我的代码中加载第二个脚本,因为它的源是动态的(即取决于远程脚本的某些结果)。

当请求的脚本被动态加载时,第二个getScript 调用会被 JavaScript 的同源策略阻止。

方案一:在html代码中包含脚本

如果可以访问 html 文件,可以添加一个带有远程脚本的脚本标记为src。因此,一个人“证明”了一个人真的想要加载这个远程脚本,而javascript将执行远程getScript调用。

<html><head>
  ...
  <script language="javascript" src="http://code.jquery.com/jquery-1.10.2.js"></script>
  <script language="javascript" src="http://example.com/script-from-other-server.js"></script>
</head><body></body></html>

为了执行executeLater 代码,可以简单地使用ready 回调:

# coffee script

executeLater = ->
  # this bit of code needs to run after the remote code has been executed.
  console.log("yehaa!")

$(document).ready(executeLater)

解决方案 2:规避 some-origin 策略

不建议这样做,但可以这样做。 有一个流行的堆栈溢出问题如何绕过同源策略:

Ways to circumvent the same-origin policy

方案3:真正等待脚本执行

如果除了同源策略之外,远程脚本确实需要很长时间才能执行到本地脚本必须等待它,可以使用 Ahmed Nuaman 的 iframe 解决方案:

https://***.com/a/18793000/2066546

【讨论】:

【参考方案2】:

这有点讨厌,但是您尝试过使用iframe 吗?这个想法很简单:

    有一个包含actionmethod 的表单,适合您尝试提出的请求。 设置表单的target(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form)指向你页面上的一个iframe,这个iframe可以隐藏。 收听iframeonload,当iframe 加载完毕后,您就可以执行您的代码了。

所以这里有一个小例子(使用 jQuery):

<form id="xform" action="http://foo.bar/foo/bar" method="get" target="xiframe">
  <input type="text" name="foo" value="bar" />
</form>
<iframe name="xiframe" id="xiframe"></iframe>
<script>
  var form = $('#xform'),
      iframe = $('#xiframe');

  iframe.load(function () 
    // run your stuff here
  );

  form.submit();
</script>

【讨论】:

感谢您提出此修复建议。据我了解,它确实允许等待脚本执行而不是成功加载。但是,正如 adeneo 在上面的评论部分所建议的那样,真正的问题是我没有考虑 js 单源策略。对此进行更正(通过将脚本标记直接包含到 html 结构中)确实解决了我的问题。 ... 现在,我不确定如何在 *** 中正确进行。我接受你的回答(因为它可能正确回答了我的问题)还是我要求 adeneo 提交答案(因为他确实在评论中确定了我的潜在问题)?谢谢! 任何你喜欢的东西!

以上是关于jQuery跨域ajax:执行时回调的主要内容,如果未能解决你的问题,请参考以下文章

JQuery - $.ajax() - 使用 JSONP 的跨域 - 仅在 IE 8 中获取“解析器错误”(在 IE 7 中工作)

Ajax 跨域和同源策略的解释和使用,使用jQuery跨域,模板引擎artTemplate的使用详细解释+案例

JQuery的Ajax跨域请求的

Jquery ajax json 不执行success的原因 坑爹

JQUERY的AJAX中 get()post()的跨域方法

jquery 使用ajax,正常返回后,不执行success的问题