2013-05-10 79 views
6

我需要捕捉來自服務器的所有響應中可能的登錄頁面,所以我已全局覆蓋Backbone.sync,以便在傳遞它們之前檢查所有錯誤。捕捉骨幹同步錯誤

Backbone.originalSync = Backbone.sync; 

Backbone.sync = function (method, model, options) { 
    var originalSuccess, originalError; 
    console.log("sync override..."); 
    // remember original success so we can call it if user logs in successfully 
    originalSuccess = options.success; 
    // proxy the error callback to first check if we get a login page back 
    originalError = options.error; 
    options.error = function (model, xhr, options) { 
     if (xhr.status === 200 && xhr.responseText === "") { 
      // parse error from empty response (jq1.9 invalid json, ok) 
      originalSuccess(model, xhr, options); 
     } else { 
      console.log("Sync error " + statusTxt + ", " + thrown.message); 
      if (xhr.status === 200 || xhr.status === 302 || xhr.status === 0) { 
       // login page returned instead of json... 
       // open a new window with relogon.html to trigger a new login 
       window.showModalDialog("../relogon.html"); 
      } else { 
       // normal error, pass along 
       if (originalError) { 
        originalError(model, xhr, options); 
       } 
      } 
     } 
    }; 

    // call the original sync 
    Backbone.originalSync(method, model, options); 
}; 

當從0.9.9變爲1.0時,這個數字變得非常糟糕。看起來像原來的Backbone.sync以不同的方式包裝它的錯誤處理程序,導致我的錯誤處理程序首先被調用,並帶有jquery xhr簽名。 我只好錯誤處理程序的簽名改成這樣:

options.error = function (xhr, statusTxt, thrown) { 

確定,所以現在它的工作原理,但我得到,我做錯了什麼的感覺。

有沒有更好的方法來做到這一點?

我試過jQuery的承諾,但我需要能夠從錯誤狀態切換到成功(當調用originalSuccess時),這似乎沒有與承諾一起工作。

+0

你可以顯示你的jQuery嘗試?這聽起來很有希望[原文如此]。 – 2013-05-10 10:50:47

回答

8

你可以建立自己的jQuery Deferred object改變默認Backbone.sync行爲

Backbone.sync = function (method, model, opts) { 
    var xhr, dfd; 

    dfd = $.Deferred(); 

    // opts.success and opts.error are resolved against the deferred object 
    // instead of the jqXHR object 
    if (opts) 
     dfd.then(opts.success, opts.error); 

    xhr = Backbone.originalSync(method, model, _.omit(opts, 'success', 'error')); 

    // success : forward to the deferred 
    xhr.done(dfd.resolve); 

    // failure : resolve or reject the deferred according to your cases 
    xhr.fail(function() { 
     if (xhr.status === 200 && xhr.responseText === "") { 
      dfd.resolve.apply(xhr, arguments); 
     } else { 
      if (xhr.status === 200 || xhr.status === 302 || xhr.status === 0) { 
       console.log('login'); 
      } 
      dfd.reject.apply(xhr, arguments); 
     } 
    }); 

    // return the promise to add callbacks if necessary 
    return dfd.promise(); 
}; 

的承諾反映您所選擇的最終狀態。

http://jsfiddle.net/AsMYQ/4/對於失敗演示,http://jsfiddle.net/AsMYQ/5/取得成功。

如果我可以

  • 你可能不應該與你的登錄操作綁得那麼緊Backbone.sync。使用事件,從骨幹或jQuery.ajaxError作爲@Andrey建議
  • 您的服務器響應應指示授權失敗,可能是一個401個狀態
  • 當你重寫同步別忘了來回報您的延期承諾/ jqXHR對象,可能出現在方便的下線
+0

謝謝,現在我看到我在嘗試延遲處理時做了什麼錯誤。關於你的建議,你可能是對的 - 我會試圖解耦relogin,更糟的是我沒有任何控制服務器響應(有一個傳統的SSO攔截所有調用) – d4kris 2013-05-13 20:28:03

+0

爲什麼你不返回xhr對象你的新同步()函數,而不是做出新的承諾? – 2014-11-10 13:25:57

+0

因爲成功和失敗的條件不是由xhr定義的條件 – nikoshr 2014-11-10 13:29:09

9

所有同步錯誤都會傳遞給模型的error事件,因此您可以收聽此事件。

http://backbonejs.org/#Events-catalog

「錯誤」(型號,XHR,選項) - 當一個模型保存在服務器上調用失敗。

要捕獲錯誤全球您可以使用http://api.jquery.com/ajaxError/

+0

是否有可能在全球範圍內收聽所有模型和集合?這個錯誤可能隨時發生,所以我想在全球範圍內處理它。無論如何,我需要捕捉錯誤並對其進行處理,而不是隻聽它,所以我不認爲這會適用於我的情況。 – d4kris 2013-05-10 10:44:46

+0

我已經用可能的解決方案更新了我的答案。 – 2013-05-10 11:24:11

+0

難道你不是在用jquery ajax處理程序在這裏混淆骨幹事件嗎? AFAIK,ajaxError與主幹錯誤事件根本沒有關係;例如,如果您手動觸發錯誤事件,則不會觸發ajaxError處理程序,並且回調的參數會有所不同 – SpoonMeiser 2016-03-29 10:19:50