81

When my website was 100% jQuery, I used to do this:

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

to set a global handler for 401 errors. Now, I use angularjs with $resource and $http to do my (REST) requests to the server. Is there any way to similarly set a global error handler with angular?

4
  • Is it a possible duplicate of AngularJS Failed Resource GET? Commented Aug 15, 2012 at 14:36
  • 1
    No, we want to do a global error 401 handler for the application Commented Aug 15, 2012 at 14:44
  • lol, have you considered that what you want but with a different http status (which you can change)? Anyhow, pkozlowski.opensource's answer shows you how to do it Commented Aug 15, 2012 at 15:39
  • No, it is a lot more like the answer of Justen...this is not a duplicate with the question you're talking Commented Aug 15, 2012 at 16:51

3 Answers 3

97

I'm also building a website with angular and I came across this same obstacle for global 401 handling. I ended up using http interceptor when I came across this blog post. Maybe you'll find it as helpful as I did.

"Authentication in AngularJS (or similar) based application.", espeo software

EDIT: final solution

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);
Sign up to request clarification or add additional context in comments.

13 Comments

Need to return $q.reject(response); when status == 401, to avoid a noisy angular error
@daniellmb. It depends. If you actually want to go to another page, not just change the view then you should actually use $window. If your login page is just another view and controller with your angular then you can use $location.path
@uriDium right my point was to use the angular provided objects so you can mock and test.
$httpProvider.responseInterceptors is now deprecated. See docs.angularjs.org/api/ng.$http#description_interceptors.
In success you need to return like return response || $q.when(response); so that if the response is empty then also a promise object is returned.
|
76

Please note that responseInterceptors have been deprecated with Angular 1.1.4. Below you can find an excerpt based on the official docs, showing the new way to implement interceptors.

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

This is how it looks in my project using 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')

6 Comments

But you will have no xhr data or other useful info in responseError interceptor. It's even unusable to decide if it's recoverable.
@zw0rk You will... inside of responseError, rejection has everything you need.
Does that last line, $httpProvider... get wrapped in a config() block?
indeed, I've edited my answer to show how I did it in my project using Coffeescript. Use js2coffee.org if you prefer it in Javascript.
Shouldn't all the reference to response under the responseError function actually be references to rejection (or maybe the parameter should have its name changed to response?
|
16

Create the file <script type="text/javascript" src="../js/config/httpInterceptor.js" ></script> with this content:

(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);
}());

1 Comment

@ThilakRaj the above code should run on every http request. So make two breakpoints in Chrome, one on the ´return response´ line and one on the ´return $q.reject´ to check that it runs as it should.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.