2014-03-05 116 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

順便說一句,如果因爲沒有其他原因,感謝您閱讀我冗長的問題,我會爲此答覆投票。 –