2015-08-18 9 views
7

implementieren Was ich will: eine Fehlerbehandlung, die global unterschiedliche HTTP-Fehler (401, 404, 500) behandelt. Es sollte nicht wichtig sein, wo oder wann ein HTTP-Fehler auftritt.Wie eine richtige globale HTTP-Fehlerbehandlung in ember

Bisher implementiert ich eine Fehler Aktion in der Anwendung Route, die auf irgendwelchen Adapter Fehler auf der Route des model Hook aufgerufen wird. Das funktioniert gut.

Was nicht abgedeckt wird, ist der Fall, wenn ich mit Datensätzen in anderen Kontexten wie record.save() arbeiten. Dort muss ich den Fehler auf dem Versprechen separat behandeln.

Außerdem habe ich nicht nur einen Standardfehlerhandler haben, sondern eher wie ein Rückfall.

Ok, bevor zu viel reden wir ein Beispiel Umsetzung meiner Anwendungsfälle haben.

Anwendung Route

Der Anwendungsfehler Aktion sollte der Standard/Ausweichfehlerbehandlung sein.

actions: { 
    error: function(error) { 
    var couldHandleError = false; 

    if (error.errors) { 
     switch (error.errors[0].status) { 
     case '401': 
      // User couldn't get authenticated. 
      // Redirect handling to login. 

      couldHandleError = true; 
      break; 
     case '404': 
     case '500': 
      // Something went unexpectedly wrong. 
      // Let's show the user a message 

      couldHandleError = true; 
      break; 
     } 
    } 

    // return true if none of the status code was matching 
    return !couldHandleError; 
    } 
} 

Einige Route

In diesem Fall wird die Anwendungsfehler Aktion aufgerufen wird.

model: function() { 
    return this.store.findAll('post'); 
} 

Einige Controller

In diesem Fall wird die Anwendungsfehler Aktion nicht aufgerufen wird.

(ich weiß, ist der folgende Code wahrscheinlich nicht sinnvoll, aber es sollte nur meine Anforderungen illustrieren)

this.store.findRecord('post', 123); 

Einige anderen Controller

In diesem Beispiel wird der Fehler Anwendung Die Aktion wird sicher nicht aufgerufen, da ich hier einen eigenen Handler verwende (catch()). Aber wie Sie in den Kommentaren sehen kann ich den Standard-Handler für alle Statuscodes anders als 404.

this.store.findRecord('post', 123).catch(function(reason) { 
    if (reason.errors[0].status === '404') { 
    // Do some specific error handling for 404 
    } else { 
    // At this point I want to call the default error handler 
    } 
}); 

So ist es eine saubere und genehmigt Art und Weise, dies zu erreichen verwenden wollen? Ich hoffe, ich konnte dir mein Problem klar machen.

Antwort

5

Sie können versuchen, etwas mit diesen Ereignissen zu tun (bitte diese Zeilen in app.js vor app Initialisierung):

Ember.onerror = function (error) { 
    console.log('Ember.onerror handler', error.message); 
}; 

Ember.RSVP.on('error', function (error) { 
    console.log('Ember.RSVP error handler', error); 
}); 

Ember.Logger.error = function (message, cause, stack) { 
    console.log('Ember.Logger.error handler', message, cause, stack); 
}; 

ich über sie von https://raygun.io/blog/2015/01/javascript-error-handling-ember-js/ gelernt, Sie dort einige Details finden.

+0

Thx, ich werde es morgen versuchen. Klingt gut bis jetzt. – val

+0

Ok, klang gut ... aber jetzt habe ich das Problem, dass ich nicht den Kontext habe, den ich brauche. Zum Beispiel muss ich zu meiner Login-Route umleiten, wenn der Benutzer nicht authentifiziert ist. In meiner Anwendungsroute konnte ich Sachen wie transitionTo() oder controllerFor() machen. Wie könnte ich es mit diesem Ansatz tun? – val

+0

@Valentin, Sie können auch einen Fehler in der Route verwenden. Für Informationen: http://guides.emberjs.com/v2.0.0/routing/loading-and-error-substates/. Lass es mich wissen, wenn es für dich funktioniert. Vielen Dank. – phkavitha

13

Ich denke, ich habe meine endgültige Lösung, die ich mit Ihnen teilen möchte. Im Grunde nahm ich die Ideen der Jungs, die meine Frage kommentierten und sie so erweiterten, dass sie meinen Bedürfnissen entsprachen.

Zuerst habe ich ein mixin mit der Hauptlogik. Da ich möchte, dass es so allgemein wie möglich ist, unterscheidet es zwischen a) Controller/Route und b) jquery/Adapterfehler.Es ist also egal, von wo Sie es aufrufen und ob Ihr Fehlerobjekt ursprünglich von einer Jquery-Ajax-Anfrage oder einem Ember-Adapter stammt.

import Ember from 'ember'; 

export default Ember.Mixin.create({ 

    ajaxError: function(error) { 
    if (!error) { 
     Ember.Logger.warn('No (valid) error object provided! ajaxError function must be called with the error object as its argument.'); 
     return; 
    } 

    // Depending whether the mixin is used in controller or route 
    // we need to use different methods. 
    var transitionFunc = this.transitionToRoute || this.transitionTo, 
     couldHandleError = false; 

    switch (this._getStatusCode(error)) { 
     case 401: 
     transitionFunc.call(this, 'auth.logout'); 
     couldHandleError = true; 
     break; 
     case 404: 
     case 500: 
     // Here we trigger a service to show an server error message. 
     // This is just an example and currently not the final implementation. 
     // this.get('notificationService').show(); 
     couldHandleError = true; 
     break; 
    } 

    // For all other errors just log them. 
    if (!couldHandleError) { 
     Ember.Logger.error(error); 
    } 
    }, 

    _getStatusCode: function(error) { 
    // First check for jQuery error object 
    var status = error.status; 

    // Check for ember adapter error object if it's not a jquery error 
    if (!status && error.errors && error.errors[0].status) { 
     status = parseInt(error.errors[0].status); 
    } 

    return status; 
    }, 

}); 

Weiter wieder geöffnet ich einige Klassen (innen app.js) diese Funktionalität global verfügbar zu machen:

import AjaxErrorMixin from 'app/mixins/ajax-error'; 

Ember.Route.reopen(AjaxErrorMixin); 
Ember.Controller.reopen(AjaxErrorMixin); 

Ember.Component.reopen({ 
    _actions: { 
    // Passing ajaxError per default 
    ajaxError: function(error) { 
     this.sendAction('ajaxError', error); 
    } 
    } 
}); 

Schließlich habe ich einige Aktionen zur Anwendung Route:

actions: { 
    error: function(error) { 
    this.send('ajaxError', error); 
    }, 

    ajaxError: function(error) { 
    this.ajaxError(error); 
    }, 
} 

Warum habe ich zwei Aktionen, die dasselbe tun? Nun, die Aktion error wird bei Fehlern auf dem Modellhook der Route aufgerufen. Ich könnte bei dieser Aktion bleiben, aber im Rest der Anwendung, wo ich diese Aktion explizit nenne, möchte ich einen aussagekräftigeren Namen. Deshalb habe ich auch eine ajaxError Aktion erstellt. Du könntest sicher mit einer Aktion bleiben.

Jetzt können Sie diese überall verwenden:

Strecke/Regler:

this.ajaxError(error);

Komponente:

this.sendAction('ajaxError', error);

Sicher, Sie müssen auch pa ss die Aktion aus der Komponente durch die Anwendung Route behandelt werden:

{{some-component ajaxError="ajaxError"}}

Dieses für verschachtelte Komponenten funktionieren auch. Sie müssen diese Aktion nicht explizit in der Datei component.js weiterleiten, da wir die Komponente erneut geöffnet und diese Aktion in übergeben haben.

Ich hoffe, ich kann anderen Menschen mit dieser Implementierung helfen. Auch jedes Feedback ist willkommen.

Verwandte Themen