2014-03-05 67 views
1

我想我会被困在写一个混乱的调度函数,但认为我会检查S.O.社区首先看看是否有人提出了一个更简单的解决方案。修改jQuery jsonp回调函数?

祝福世界银行有一个开放的API,但他们有一些实施问题。首先问题是他们的服务器没有实现CORS Access-Control-Allow-Origin: *,所以这意味着JSONP而不是JSON。这不会是一个问题,除非他们不要保存回调函数的情况下!举一个具体的例子,我做我的代码如下要求:(是的,他们所使用的参数prefix代替传统callback的)

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

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...),并且通过调用原始文件不做任何事情。黑客商是如此之高,我的头旋转,但我已经验证了这样做的工作:

$.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)"); 
     } 
    } 
    } 
}); 

我真的希望我失去了一些东西很简单,有人很善良会指出来给我。

回答

4

你称为hack的最后一种选择听起来像是一种强大的简单方式来利用所有jQuery为你做的事情,并且只是通过使你自己的函数小写,并从它调用混合的case来解决一个case case问题。除了让世界银行修理他们的服务器之外,这似乎是对我做事情最不起作用的方式。我看不到任何更好的解决方法。

如果jQuery回调函数在beforeSend时间已经存在,那么您所要做的就是创建一个小写字母的全局变量,并在其中添加对混合函数的引用。你甚至不需要创建一个函数体。

所以,如果你在URL中beforeSend看到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; 
     } 
    }); 
})(); 
+0

感谢您的鼓励;这让我感觉好一点。但需要注意的一点是,jQuery实际上并没有定义jsonp回调('jQuery ...'),直到**调用'beforeSend'之后的某个点**。所以只是创建全局变量将不起作用。但是,如果这是我留下的,创建一个动态函数不会太难。 –

+0

@StephenThomas - 啊,好的。稍微创建小写回调的工作稍微多一些,但听起来你知道该怎么做。 – jfriend00

+0

顺便说一句,如果因为没有其他原因,感谢您阅读我冗长的问题,我会为此答复投票。 –