2013-05-10 13 views
6

Potrzebowałem złapać możliwą stronę logowania we wszystkich odpowiedziach od serwera, więc przesłoniłem Backbone.sync globalnie, więc mogę sprawdzić wszystkie błędy przed ich przekazaniem.Łapanie błędów synchronizacji kręgosłupa

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); 
}; 

To zepsuło się, przechodząc od 0.9.9 do 1.0. Wygląda na to, że oryginalny Backbone.sync inaczej obchodzi obsługę błędów, powodując, że mój program obsługi błędów jest wywoływany jako pierwszy, z sygnaturą jQuery xhr. musiałem zmienić podpis obsługi błędów do tego:

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

Ok, więc teraz to działa, ale mam wrażenie, że robię coś złego.

Czy jest lepszy sposób to zrobić?

Próbowałem z jquery obietnic, ale muszę być w stanie przejść od stanu błędu do sukcesu (podczas wywoływania originalSuccess), który nie wydaje się działać z obietnicami.

+0

Czy możesz pokazać swoją próbę jQuery? Brzmi obiecująco [sic]. –

Odpowiedz

8

Możesz budować własną jQuery Deferred object do zmiany domyślnej Backbone.sync zachowanie ruchowe

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(); 
}; 

Obietnica odzwierciedla stan końcowy wybrać.

http://jsfiddle.net/AsMYQ/4/ dla demo awarii, http://jsfiddle.net/AsMYQ/5/ za sukces.

I jeśli może

  • prawdopodobnie nie powinien wiązać tak mocno Backbone.sync z obsługi logowania. Użyj zdarzenia, z Backbone lub jQuery.ajaxError jak @Andrey zasugerował
  • swoją odpowiedź serwera powinna wskazywać na awarię zezwoleń, chyba 401 Stan
  • nie zapomnij, aby przywrócić odroczony obietnicę/przedmiot jqXHR gdy zastępują synchronizacji, które mogą pochodzić przydaje się linia
+0

Dziękuję, teraz widzę, co zrobiłem źle, gdy próbowałem z odroczonym.Co do twoich sugestii, masz prawdopodobnie rację - postaram się oddzielić relogin, co gorsze, nie mam żadnej kontroli nad odpowiedziami serwera (istnieje starsza SSO przechwytująca wszystkie połączenia) – d4kris

+0

Dlaczego nie zwrócisz obiektu xhr z twoja nowa funkcja sync(), zamiast składać nową obietnicę? –

+0

Ponieważ warunki sukcesu i niepowodzenia nie są określone przez xhr – nikoshr

9

Wszystkie błędy synchronizacji są przekazywane do zdarzenia modelu error, więc możesz posłuchać tego wydarzenia.

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

"error" (model, XHR, opcje) - gdy model Zachowajmy połączenia nie powiedzie się na serwerze.

Aby przechwycić błąd globalnie można użyć http://api.jquery.com/ajaxError/

+0

Czy można słuchać wszystkich modeli i kolekcji na całym świecie? Ten błąd może się zdarzyć w dowolnym momencie, więc chciałbym go obsłużyć na całym świecie. W każdym razie, muszę uchwycić błąd i poradzić sobie z nim, nie tylko go słuchać, więc nie sądzę, by to działało w moim scenariuszu. – d4kris

+0

Zaktualizowałem swoją odpowiedź z możliwym rozwiązaniem. –

+0

Czy nie mylicie kręgosłupa z obsługą jquery ajax? AFAIK, ajaxError nie jest w ogóle związany ze zdarzeniem błędu szkieletu; jeśli ręcznie wyzwolisz zdarzenie błędu, na przykład, nie uruchomisz obsługi ajaxError, a argumenty do wywołania zwrotnego będą różne – SpoonMeiser

Powiązane problemy