Глобальный обработчик ошибок 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);

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

Но в перехватчике 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», чтобы проверить, работает ли она должным образом.
— Ян-Терье Соренсен
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.