29

I know how to intercept ALL requests, but I only want to intercept requests from my resources.

Does anyone know how to do this?

services.config(['$httpProvider',function($httpProvider) {
    $httpProvider.interceptors.push('myHttpInterceptor');
}]);

services.factory("userPurchased", function ($resource) {
    return $resource("/api/user/purchases/:action/:item", 
        {}, 
        {
            'list': {method: 'GET', params: {action: 'list'}, isArray: false},
            'save': {method: 'PUT', params: {item: '@item'}},
            'remove': {method: 'DELETE', params: {item: '@item'}},
        }
    );
});

services.factory('myHttpInterceptor', function($q,$rootScope) {
    // $rootScope.showSpinner = false;
    return {

      response: function(response) {
        $rootScope.showSpinner = false;
        // do something on success
        console.log('success');
        console.log('status', response.status);
        //return response;
        return response || $q.when(response);
      },

     responseError: function(response) {
        // do something on error
        $rootScope.showSpinner = true;
        console.log('failure');
        console.log('status', response.status)
        //return response;
        return $q.reject(response);
      }
    };
  });

7 Answers 7

24

If you want to intercept only requests from specific resources, you can use optional interceptor property of $request action. Angular's documentation see here (Usage>actions)

JavaScript

angular.module('app', ['ngResource']).
  factory('resourceInterceptor', function() {
    return {
      response: function(response) {
        console.log('response intercepted: ', response);
      }
    }
  }).
  factory('resourceService', ['$resource', 'resourceInterceptor', function($resource, resourceInterceptor) {
    return $resource(":name", 
        {}, 
        {
            'list': {method: 'GET', isArray: false, interceptor: resourceInterceptor}
        }
    );
  }]).
  run(['resourceService', '$http', function(resourceService, $http) {
    resourceService.list({name: 'list.json'}); // <= intercepted
    $http.get('list.json'); // <= not intercepted
  }]);

Plunker: http://plnkr.co/edit/xjJH1rdJyB6vvpDACJOT?p=preview

Sign up to request clarification or add additional context in comments.

1 Comment

This is not working when i push multiple interceptors to httpProvider. I want to call only a sepecific interceptor, which i am doing as above , but the request method gets called of all the interceptors i registered.
23

The only way I know of doing this it to just filter out the requests you want in the response handler.

e.g.

...
response: function(response) {
    if(response.config.url.startsWith('/api/')) {
        //Do your custom processing here
    }

    return response;
}
...

Polyfill for string.startsWith()

//Taken from http://stackoverflow.com/questions/646628/javascript-startswith
if (typeof(String.prototype.startsWith) === 'undefined') {
    String.prototype.startsWith = function(str) {
        return this.slice(0, str.length) === str;
    };
}

2 Comments

If you're using direct urls, good old indexOf('/api/') > -1 should also work
This answer works only if the rest api is well named using '/api/'. I prefer checking http header for content-type (such as XML or JSON)
1

My preferred way is to use an HTTP interceptor which replaces a "magic" Authorization header with the current OAuth token. The code below is OAuth specific, but remedying that is a simple exercise for the reader.

// Injects an HTTP interceptor that replaces a "Bearer" authorization header
// with the current Bearer token.
module.factory('oauthHttpInterceptor', function (OAuth) {
  return {
    request: function (config) {
      if (config.headers.Authorization === 'Bearer') {
        config.headers.Authorization = 'Bearer ' + btoa(OAuth.accessToken);
      }
      return config;
    }
  };
});

module.config(function ($httpProvider) {
  $httpProvider.interceptors.push('oauthHttpInterceptor');
});

2 Comments

This doesn't really answer the question which was asked
It does - just supply an Authorization header of "Bearer" / "magic string" with your requests (and no others), and the interceptor will be called. You could use the accepted answer - and this is probably more obvious - but will mean that you're tying that interceptor in everywhere - whereas the method in my example offers indirection.
0
/**object single interceptor**/ 
 function SingleCallInterceptor(callbacks){

    this.receive=function(response) {

      switch (response.status) {

        case 200:

          callbacks.success(apiResponse);

          break;

        default :

          callbacks.error(response);
      }

    }

  }


var successfn=function(response){  //i have my response}

var errorfn=function(response){  //i have my error}

var responseInterceptor=new SingleCallInterceptor({success:successfn,error:errorfn});

        $http({

        url: "www.itsdirtysolutioniknow.it,

        method: "GET",

        dataType: "JSONP",

      }).then(responseInterceptor.receive,responseInterceptor.receive);

1 Comment

This is just providing a callback function. How would one use it as a http call interceptor?
0

By default angular sends and receives application/json headers. You can get this on the HTTP response header like :

services.config(['$httpProvider',function($httpProvider) {
    $httpProvider.interceptors.push('myHttpInterceptor');
}]);

services.factory("userPurchased", function ($resource) {
    return $resource("/api/user/purchases/:action/:item", 
        {}, 
        {
            'list': {method: 'GET', params: {action: 'list'}, isArray: false},
            'save': {method: 'PUT', params: {item: '@item'}},
            'remove': {method: 'DELETE', params: {item: '@item'}},
        }
    );
});

services.factory('myHttpInterceptor', function($q,$rootScope) {
    // $rootScope.showSpinner = false;
    return {

      response: function(response) {
        // use this line to if you are receiving json, else use xml or any other type
        var isJson = response.config.headers.Accept.indexOf('json')>-1;
        $rootScope.showSpinner = false;
        // do something on success
        console.log('success');
        console.log('status', response.status);
        //return response;
        return response || $q.when(response);
      },

     responseError: function(response) {
        // use this line to if you are receiving json, else use xml or any other type
        var isJson = response.config.headers.Accept.indexOf('json')>-1;
        // do something on error
        $rootScope.showSpinner = true;
        console.log('failure');
        console.log('status', response.status)
        //return response;
        return $q.reject(response);
      }
    };
  });

Comments

0

I just came across an issue where googleapis also uses an Authorization header, and was throwing a 401 response because the JWT I use on my server wasn't valid for their server (obviously), and my code was set to automatically remove my token and redirect the person to the login page. (It wasn't written super well, since ANY 401 response would log my user out).

I just came up with this solution in my request method in the interceptor, which I think works pretty well:

.service('authInterceptor', ["$q", "$location", "tokenService", function($q, $location, tokenService){
    this.request = function(config) {
//        console.log($location.host());
        var token = tokenService.getToken();
        if(token && config.url.indexOf($location.host()) > -1) {
            config.headers = config.headers || {};
            config.headers.Authorization = "Bearer " + token
        }
        return config
    }

    this.responseError = function(response) {
//        console.log(response.config.url)
        if (response.status === 401) {
            tokenService.removeToken();
            $location.path('/login')
        }
        return $q.reject(response);
    }
}])

The request method checks if I have a token in local storage AND if the request url is being made to the same host (which I get from $location.host()) as the one my page is being served up on. This works for localhost as well as whatever URL I end up deploying my site on.

I haven't done much testing with this, so if anyone finds a flaw in this please let me know :)

Comments

0

I know it is an old question but I wanted to provide a solution if you have pushed multiple $http Interceptors and want them to continue working, return your response so the Interceptor chain continues:

    module.factory('resourceInterceptor', ['$q', function($q) {
        return {
            response: function(response) {
                // do your conditional logic here
                if (...) {
                    return $q.resolve(response);
                }
            },
            responseError: function(response) {
                // do your conditional logic here   
                if (...) {
                    return $q.reject(response);
                }
            }
        };
    }]);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.