【问题标题】:Modifying jQuery jsonp callback function?修改 jQuery jsonp 回调函数?
【发布时间】:2014-04-06 20:36:33
【问题描述】:

我想我会被困在编写一个凌乱的调度函数,但我想我会检查 S.O.社区首先看看是否有人提出了更简单的解决方案。

感谢世界银行有一个开放的 API,但他们有一些实施问题。第一个问题是他们的服务器没有实现 CORS Access-Control-Allow-Origin: *,所以这意味着 JSONP 而不是 JSON。这不是问题,只是它们保留回调函数的大小写!举一个具体的例子,我在我的代码中提出以下要求:

var deferredRegionsRequest = $.getJSON(
    "http://api.worldbank.org/regions/?prefix=?",
    {format: "jsonp"}
);

(是的,他们使用参数prefix 而不是传统的callback。)

jQuery 尽职尽责地创建一个随机回调函数并发出 AJAX 请求:

http://api.worldbank.org/regions/?prefix=jQuery18308848262811079621_1393981029347&format=jsonp&_=1393981029990

注意回调函数有一个大写的Q

然而,世界银行返回的响应已将该回调重命名为全小写!

jquery18308848262811079621_1393981029347([
    { "page": "1", "pages": "1", "per_page": "50", "total": "32" },
    [ {
        "id": "",
        "code": "AFR",
        "name": "Africa"
      }, {
...

显然这行不通。如果我只是发出一个请求,提供我自己的回调函数并使用$.ajax()jsonpCallback 参数不会太痛苦。不幸的是,我需要遍历和循环他们的 REST API,所以我将进行数十个(并行)API 调用。我检查了一个自定义回调,并且 this 设置为全局 window 对象,因此单个回调函数似乎没有任何明显的方法来管理多个响应。看起来我可能会陷入混乱的自定义调度程序实现中,我真的很想避免这种情况。

到目前为止,我想出的唯一替代方法是定义一个 beforeSend 回调,它采用完全填充的 URL,解析它以找到回调函数 (jQuery...),动态创建一个新的回调函数原始版本 (jquery...) 的所有小写版本,并且调用原始版本不执行任何操作。 hack 商数太高了,我头晕目眩,但我已经证实这确实有效:

$.ajaxSetup({
  beforeSend: function(xhr, settings) {
    var prefix = settings.url.match(/prefix=(.*?)&/);
    if (prefix.length > 1) {
      var callback = prefix[1];
      if (callback !== callback.toLowerCase()) {
        window[callback.toLowerCase()] = 
          new Function("response", callback + "(response)");
      }
    }
  }
});

我当然希望我遗漏了一些非常简单的东西,并且非常好心的人会向我指出。

【问题讨论】:

    标签: jquery ajax callback jsonp


    【解决方案1】:

    您称为 hack 的最后一个替代方法听起来像是一种非常简单的方法,可以利用 jQuery 为您所做的所有事情,只需通过创建自己的小写函数并从中调用混合大小写的函数来解决一个案例问题。除了让世界银行修复他们的服务器之外,这对我来说似乎是最不生硬的做事方式。我看不到任何更好的解决方法。

    如果 jQuery 回调函数在beforeSend 时间已经存在,那么您需要做的就是创建一个小写名称的全局变量,并将对混合大小写函数的引用放入其中。您甚至不必创建函数体。

    所以,如果您在 beforeSend 的 URL 中看到 jQuery18308848262811079621_1393981029347,那么您只需:

    window.jquery18308848262811079621_1393981029347 = jQuery18308848262811079621_1393981029347;
    

    我想可能需要eval() 才能完成这项工作,因为您将函数的名称作为字符串。或者也许这里的一位天才可以弄清楚如何在没有eval() 的情况下创建那行代码。


    另一种选择可能是为您使用的 jQuery 库制作单个字符补丁,以便它只输出小写字符串。

    我认为“jQuery”字符串部分来自于此:

    jQuery.extend({
    // Unique for each copy of jQuery on the page
    expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ),
    

    虽然需要一些调试来确认。


    或者,看起来可能有一个回调函数创建了可以修改或替换的 jsonpCallback 名称:

    // Default jsonp settings
    jQuery.ajaxSetup({
        jsonpCallback: function() {
            var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( ajax_nonce++ ) );
            this[ callback ] = true;
            return callback;
        }
    });
    

    我发现这可以在我的演示 JSONP 应用程序http://jsfiddle.net/jfriend00/UM9NL/ 中工作:

    $.ajaxSetup({
      beforeSend: function(xhr, settings) {
          var origCallback = settings.jsonpCallback;
          settings.url = settings.url.replace(/=jQuery/, "=jquery");
          window[origCallback.toLowerCase()] = function() {
              window[origCallback].apply(this, arguments);
          }
      }
    });
    

    而且,这也适用http://jsfiddle.net/jfriend00/GXte2/

    // Default jsonp settings
    (function() {
        var myajax_nonce = jQuery.now();
        jQuery.ajaxSetup({
            jsonp: "callback",
            jsonpCallback: function() {
                var callback = ( jQuery.expando.toLowerCase() + "_" + ( myajax_nonce++ ) );
                this[ callback ] = true;
                return callback;
            }
        });
    })();
    

    【讨论】:

    • 感谢鼓励;这让我感觉好一点。不过要注意的一点是,jQuery 直到 之后 调用beforeSend 之后才真正定义 jsonp 回调 (jQuery...)。所以仅仅创建全局变量是行不通的。但是,如果这是我所剩下的,那么创建一个动态函数不会太难。
    • @StephenThomas - 啊,好的。那时创建小写回调的工作会稍微多一些,但听起来你知道该怎么做。
    • 顺便说一句,如果没有其他原因,我会投票赞成这个答案,感谢您阅读我冗长的问题。
    • @StephenThomas - 我在答案中添加了另一个选项。您可以为包含的 jQuery 库制作单个字符补丁,以将“Q”更改为小写。
    • 基于@jfriend00 的cmets,我决定尝试一下这个hack。它确实有效,我已经用经过测试的代码更新了这个问题。我仍然对使用 jQuery 文档recommend against 感到紧张,但这似乎是最干净的选择。我会让这个静置一天左右,看看是否有人想出更清洁的东西,否则我会接受这个答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-03
    • 2013-04-29
    • 2019-12-07
    • 2013-10-17
    • 1970-01-01
    • 2013-05-10
    相关资源
    最近更新 更多