Глобальний обробник помилок 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 Failed Resource GET ?
MilkyWayJoe

1
Ні, ми хочемо зробити глобальний обробник помилок 401 для програми
cricardol

ха-ха, ти вважав, що ти хочеш, але з іншим статусом http (який ти можеш змінити)? Так чи інакше, відповідь pkozlowski.opensource показує, як це зробити
MilkyWayJoe

Ні, це набагато більше схоже на відповідь Юстена ... це не дублікат запитання, про яке ви говорите
cricardol

Відповіді:


97

Я також будую веб-сайт з кутовим, і я зіткнувся з цією ж перешкодою для глобальної обробки 401. У підсумку я використав перехоплювач http, коли натрапив на цю публікацію в блозі. Можливо, ви знайдете це так само корисно, як і я.

"Аутентифікація в додатку на основі AngularJS (або подібного)." , espeo програмне забезпечення

EDIT: остаточне рішення

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 (відповідь); коли статус == 401, щоб уникнути шумної кутової помилки
s_t_e_v_e

1
@daniellmb. Це залежить. Якщо ви насправді хочете перейти на іншу сторінку, а не просто змінити вигляд, тоді вам слід скористатися $ window. Якщо ваша сторінка входу - це просто інший вигляд та контролер з вашим
angular,

1
Правильно, @uriDium, я мав на увазі використовувати кутові передбачені об’єкти, щоб ви могли знущатись і тестувати.
daniellmb

22
$ httpProvider.responseInterceptors тепер застарілий. Див. Docs.angularjs.org/api/ng.$http#description_interceptors .
кварцмо

1
Успішно вам потрібно повернути return response || $q.when(response);так, щоб, якщо відповідь порожня, тоді також повертався об'єкт-обіцянка.
Ashish Gaur,

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

Але у вас не буде даних xhr чи іншої корисної інформації як перехоплювач responseError. Навіть неможливо вирішити, чи можна це відновити.
zw0rk,

1
@ zw0rk Ви ... всередині responseError, rejectionмаєте все необхідне.
Ленґдон,

$httpProvider...Цей останній рядок загортається в config()блок?
delwin

справді, я відредагував свою відповідь, щоб показати, як я це зробив у своєму проекті за допомогою Coffeescript. Використовуйте js2coffee.org, якщо вам більше подобається в Javascript.
MikeR

Якщо не всі посилання на responseпід responseErrorфункції на насправді бути посилання на rejection(або , можливо , параметр повинен бути його назва було змінено на response?
Adam Нофсінгер

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, одну на рядку «відповідь на повернення» і одну на «повернення $ q.reject», щоб перевірити, чи працює вона належним чином.
Jan-Terje Sørensen
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.