Глобальный обработчик ошибок Ajax с AngularJS

82

Когда мой сайт был на 100% jQuery, я делал это:

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

чтобы установить глобальный обработчик для 401 ошибки. Теперь я использую angularjs с $resourceи $httpделать свои (REST) запросы к серверу. Есть ли способ аналогичным образом установить глобальный обработчик ошибок с помощью angular?

крикардол
источник
Это возможный дубликат отказавшего ресурса AngularJS GET ?
MilkyWayJoe
1
Нет, мы хотим сделать глобальный обработчик ошибки 401 для приложения
cricardol
lol, вы подумали о том, что хотите, но с другим статусом http (который вы можете изменить)? Во всяком случае, ответ pkozlowski.opensource показывает вам, как это сделать
MilkyWayJoe
Нет, это больше похоже на ответ Джастена ... это не дубликат вопроса, который вы говорите
крикардол

Ответы:

97

Я также создаю веб-сайт с angular, и я столкнулся с тем же препятствием для глобальной обработки 401. Я закончил тем, что использовал http-перехватчик, когда наткнулся на это сообщение в блоге. Может быть, вы найдете его таким же полезным, как и я.

«Аутентификация в приложении на основе AngularJS (или аналогичного)». , программное обеспечение espeo

РЕДАКТИРОВАТЬ: окончательное решение

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
источник
4
Необходимо вернуть $ q.reject (ответ); когда status == 401, чтобы избежать шумной угловой ошибки
s_t_e_v_e
1
@daniellmb. Это зависит. Если вы действительно хотите перейти на другую страницу, а не просто изменить вид, вам следует использовать $ window. Если ваша страница входа - это просто еще один вид и контроллер с вашим angular, вы можете использовать $ location.path
uriDium
1
@uriDium правильно, я хотел использовать объекты angular, чтобы вы могли имитировать и тестировать.
daniellmb 04
22
$ httpProvider.responseInterceptors больше не рекомендуется. См. Docs.angularjs.org/api/ng.$http#description_interceptors .
quartzmo
1
В случае успеха вам нужно вернуть как, return response || $q.when(response);чтобы, если ответ пуст, также возвращался объект обещания.
Ашиш Гаур,
77

Обратите внимание, что responseInterceptors устарела в Angular 1.1.4. Ниже вы можете найти отрывок из официальных документов. , показывающий новый способ реализации перехватчиков.

$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');

Вот как это выглядит в моем проекте с использованием Coffeescript:

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
источник
Но в перехватчике responseError у вас не будет данных xhr или другой полезной информации. Даже невозможно решить, можно ли его восстановить.
zw0rk
1
@ zw0rk У вас будет ... внутри responseError, rejectionесть все , что вам нужно.
Лэнгдон
Оборачивается ли последняя строка $httpProvider...в config()блок?
delwin
действительно, я отредактировал свой ответ, чтобы показать, как я это сделал в своем проекте с использованием Coffeescript. Используйте js2coffee.org, если предпочитаете его в Javascript.
MikeR
Разве все ссылки responseна responseErrorфункцию не должны быть ссылками на rejection(или, может быть, имя параметра должно быть изменено на response?
Адам Нофсингер,
16

Создайте файл <script type="text/javascript" src="../js/config/httpInterceptor.js" ></script>с таким содержимым:

(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);
}());
Ян-Терье Соренсен
источник
@ThilakRaj приведенный выше код должен запускаться при каждом HTTP-запросе. Так что создайте две точки останова в Chrome, одну на строке «return response» и одну на «return $ q.reject», чтобы проверить, работает ли она должным образом.
Ян-Терье Соренсен