Globaler Ajax-Fehlerbehandler mit AngularJS

82

Als meine Website zu 100% aus jQuery bestand, habe ich Folgendes getan:

$.ajaxSetup({
    global: true,
    error: function(xhr, status, err) {
        if (xhr.status == 401) {
           window.location = "./index.html";
        }
    }
});

um einen globalen Handler für 401-Fehler festzulegen. Jetzt verwende ich anglejs mit $resourceund $http, um meine (REST-) Anforderungen an den Server zu erledigen. Gibt es eine Möglichkeit, einen globalen Fehlerbehandler auf ähnliche Weise mit Angular festzulegen?

Cricardol
quelle
Ist es ein mögliches Duplikat von AngularJS Failed Resource GET ?
MilkyWayJoe
1
Nein, wir möchten einen globalen Fehler 401-Handler für die Anwendung
ausführen
lol, hast du dir überlegt, was du willst, aber mit einem anderen http-Status (den du ändern kannst)? Wie auch immer, die Antwort von pkozlowski.opensource zeigt Ihnen, wie es geht
MilkyWayJoe
Nein, es ist viel mehr wie die Antwort von Justen ... dies ist kein Duplikat mit der Frage, die Sie sprechen
Cricardol

Antworten:

97

Ich baue auch eine Website mit Winkel und bin auf dasselbe Hindernis für die globale 401-Handhabung gestoßen. Ich habe schließlich http interceptor verwendet, als ich auf diesen Blog-Beitrag gestoßen bin. Vielleicht finden Sie es genauso hilfreich wie ich.

"Authentifizierung in AngularJS (oder einer ähnlichen) basierten Anwendung." , Espeo-Software

EDIT: endgültige Lösung

angular.module('myApp', ['myApp.filters', 'myApp.services', 'myApp.directives'], function ($routeProvider, $locationProvider, $httpProvider) {

    var interceptor = ['$rootScope', '$q', function (scope, $q) {

        function success(response) {
            return response;
        }

        function error(response) {
            var status = response.status;

            if (status == 401) {
                window.location = "./index.html";
                return;
            }
            // otherwise
            return $q.reject(response);

        }

        return function (promise) {
            return promise.then(success, error);
        }

    }];
    $httpProvider.responseInterceptors.push(interceptor);
Justen
quelle
4
Müssen $ q.reject (Antwort) zurückgeben; wenn status == 401, um einen lauten Winkelfehler zu vermeiden
s_t_e_v_e
1
@daniellmb. Es hängt davon ab, ob. Wenn Sie tatsächlich zu einer anderen Seite wechseln möchten, ändern Sie nicht nur die Ansicht, sondern sollten auch $ window verwenden. Wenn Ihre Anmeldeseite nur eine andere Ansicht und ein anderer Controller mit Ihrem Winkel ist, können Sie $ location.path
uriDium
1
@uriDium richtig mein Punkt war, die eckigen bereitgestellten Objekte zu verwenden, damit Sie verspotten und testen können.
Daniellmb
22
$ httpProvider.responseInterceptors ist jetzt veraltet. Siehe docs.angularjs.org/api/ng.$http#description_interceptors .
Quarzmo
1
Im Erfolg müssen Sie wie return response || $q.when(response);folgt zurückgeben, damit bei einer leeren Antwort auch ein Versprechen-Objekt zurückgegeben wird.
Ashish Gaur
77

Bitte beachten Sie, dass responseInterceptors mit Angular 1.1.4 veraltet sind. Unten finden Sie einen Auszug, der auf den offiziellen Dokumenten basiert und die neue Methode zur Implementierung von Interceptors zeigt.

$provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
  return {
    'response': function(response) {
      // do something on success
      return response || $q.when(response);
    },

   'responseError': function(rejection) {
      // do something on error
      if (canRecover(rejection)) {
        return responseOrNewPromise;
      }
      return $q.reject(rejection);
    }
  };
});

$httpProvider.interceptors.push('myHttpInterceptor');

So sieht es in meinem Projekt mit Coffeescript aus:

angular.module("globalErrors", ['appStateModule']).factory "myHttpInterceptor", ($q, $log, growl) ->
  response: (response) ->
    $log.debug "success with status #{response.status}"
    response || $q.when response

  responseError: (rejection) ->
    $log.debug "error with status #{rejection.status} and data: #{rejection.data['message']}"
    switch rejection.status
      when 403
        growl.addErrorMessage "You don't have the right to do this"
      when 0
        growl.addErrorMessage "No connection, internet is down?"
      else
        growl.addErrorMessage "#{rejection.data['message']}"

    # do something on error
    $q.reject rejection

.config ($provide, $httpProvider) ->
  $httpProvider.interceptors.push('myHttpInterceptor')
MikeR
quelle
Sie haben jedoch keine xhr-Daten oder andere nützliche Informationen im responseError-Interceptor. Es ist sogar unbrauchbar zu entscheiden, ob es wiederherstellbar ist.
zw0rk
1
@ zw0rk Du wirst ... drinnen responseError, rejectionhat alles was du brauchst.
Langdon
Wird diese letzte Zeile $httpProvider...in einen config()Block eingeschlossen?
Delwin
In der Tat habe ich meine Antwort bearbeitet, um zu zeigen, wie ich es in meinem Projekt mit Coffeescript gemacht habe. Verwenden Sie js2coffee.org, wenn Sie es in Javascript bevorzugen.
MikeR
Sollten nicht alle Verweise auf responseunter der responseErrorFunktion tatsächlich Verweise auf sein rejection(oder sollte der Name des Parameters in geändert werden response?
Adam Nofsinger
16

Erstellen Sie die Datei <script type="text/javascript" src="../js/config/httpInterceptor.js" ></script>mit diesem Inhalt:

(function(){
  var httpInterceptor = function ($provide, $httpProvider) {
    $provide.factory('httpInterceptor', function ($q) {
      return {
        response: function (response) {
          return response || $q.when(response);
        },
        responseError: function (rejection) {
          if(rejection.status === 401) {
            // you are not autorized
          }
          return $q.reject(rejection);
        }
      };
    });
    $httpProvider.interceptors.push('httpInterceptor');
  };
  angular.module("myModule").config(httpInterceptor);
}());
Jan-Terje Sørensen
quelle
@ThilakRaj Der obige Code sollte bei jeder http-Anfrage ausgeführt werden. Erstellen Sie also zwei Haltepunkte in Chrome, einen in der Zeile "Rückgabe" und einen in der Zeile "Rückgabe $ q.reject", um zu überprüfen, ob er ordnungsgemäß ausgeführt wird.
Jan-Terje Sørensen