18

How can I stop a request in Angularjs interceptor.

Is there any way to do that?

I tried using promises and sending reject instead of resolve !

.factory('connectionInterceptor', ['$q', '$timeout',
   function($q, $timeout) {
    var connectionInterceptor = {
        request: function(config) {
            var q = $q.defer();
            $timeout(function() {
                q.reject();
            }, 2000)
            return q.promise;
            // return config;
        }
    }
    return connectionInterceptor;
  }
])
.config(function($httpProvider) {
   $httpProvider.interceptors.push('connectionInterceptor');
});
T J
  • 42,762
  • 13
  • 83
  • 138
vipulsodha
  • 624
  • 1
  • 9
  • 27
  • 1
    Post the code that you tried. Otherwise, we have no way of explaining you why it doesn't work, and how to fix it. – JB Nizet Aug 24 '14 at 15:57
  • @JBNizet added ! Please check the code ! – vipulsodha Aug 24 '14 at 17:07
  • Not sure why you're waiting 2 seconds, but your code works fine. No HTTP request is sent. See http://plnkr.co/edit/x4YGC7l4B66RGTmWB7Ts?p=preview. Open your dev tools, and check your network tab: no request to README is sent. Now comment out the registration of the interceptor and do the same test, and you'll see the request going out, and the success alert displayed. – JB Nizet Aug 24 '14 at 17:19
  • the prob I am getting is when I push the service into into the interceptor i get a blank page and no error anywhere ! Any idea where i am going wrong ? @JBNizet – vipulsodha Aug 24 '14 at 17:25
  • 2
    Well, be aware that ALL ajax requests go through your interceptor, including the ones loading the html templates. If that's not the problem, post a plunkr that reproduces the problem. – JB Nizet Aug 24 '14 at 17:30
  • @JBNizet Ohk ! That is the problem ! SO how should I restrict it for certain requests ?? – vipulsodha Aug 24 '14 at 17:33
  • 1
    check the value of `config.url`. – JB Nizet Aug 24 '14 at 17:36

5 Answers5

10

I ended up bypassing angular XHR call with the following angular Interceptor:

function HttpSessionExpiredInterceptor(sessionService) {
    return {
        request: function(config) {
            if (sessionService.hasExpired()) {
                /* Avoid any other XHR call. Trick angular into thinking it's a GET request.
                 * This way the caching mechanism can kick in and bypass the XHR call.
                 * We return an empty response because, at this point, we do not care about the
                 * behaviour of the app. */
                if (_.startsWith(config.url, '/your-app-base-path/')) {
                    config.method = 'GET';
                    config.cache = {
                        get: function() {
                            return null;
                        }
                    };
                }
            }

            return config;
        }
    };
}

This way, any request, POST, PUT, ... is transformed as a GET so that the caching mechanism can be used by angular. At this point, you can use your own caching mechanism, in my case, when session expires, I do not care anymore about what to return.

jtheoof
  • 585
  • 6
  • 10
7

The $http service has an options timeout to do the job. you can do like:

angular.module('myApp')
    .factory('httpInterceptor', ['$q', '$location',function ($q, $location) {
        var canceller = $q.defer();
        return {
            'request': function(config) {
                // promise that should abort the request when resolved.
                config.timeout = canceller.promise;
                return config;
            },
            'response': function(response) {
                return response;
            },
            'responseError': function(rejection) {
                if (rejection.status === 401) {
                    canceller.resolve('Unauthorized'); 
                    $location.url('/user/signin');
                }
                if (rejection.status === 403) {
                    canceller.resolve('Forbidden');  
                    $location.url('/');
                }
                return $q.reject(rejection);
            }

        };
    }
    ])
    //Http Intercpetor to check auth failures for xhr requests
   .config(['$httpProvider',function($httpProvider) {
        $httpProvider.interceptors.push('httpInterceptor');
    }]);
Whisher
  • 31,320
  • 32
  • 120
  • 201
1

Not sure if it is possible in general. But you can start a $http request with a "canceler".

Here is an example from this answer:

var canceler = $q.defer();
$http.get('/someUrl', {timeout: canceler.promise}).success(successCallback);
// later...
canceler.resolve();  // Aborts the $http request if it isn't finished.

So if you have control over the way that you start your request, this might be an option.

Community
  • 1
  • 1
Philipp Claßen
  • 41,306
  • 31
  • 146
  • 239
1

Here is what works for me, especially for the purposes of stopping the outgoing request, and mocking the data:


app
  .factory("connectionInterceptor", [
    "$q",
    function ($q) {
      return {
        request: function (config) {
          // you can intercept a url here with (config.url == 'https://etc...') or regex or use other conditions
          if ("conditions met") {
            config.method = "GET";
            // this is simulating a cache object, or alternatively, you can use a real cache object and pre-register key-value pairs,
            // you can then remove the if block above and rely on the cache (but your cache key has to be the exact url string with parameters)
            config.cache = {
              get: function (key) {
                // because of how angularjs $http works, especially older versions, you need a wrapping array to get the data
                // back properly to your methods (if your result data happens to be an array). Otherwise, if the result data is an object
                // you can pass back that object here without any return codes, status, or headers.
                return [200, mockDataResults, {}, "OK"];
              },
            };
          }
          return config;
        },
      };
    },
  ])
  .config(function ($httpProvider) {
    $httpProvider.interceptors.push("connectionInterceptor");
  });

If you are trying to mock a result like

[42, 122, 466]

you need to send an array with some http params back, its just how the ng sendReq() function is written unfortunately. (see line 1414 of https://github.com/angular/angular.js/blob/e41f018959934bfbf982ba996cd654b1fce88d43/src/ng/http.js#L1414 or snippet below)

        // from AngularJS http.js

        // serving from cache
        if (isArray(cachedResp)) {
          resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3], cachedResp[4]);
        } else {
          resolvePromise(cachedResp, 200, {}, 'OK', 'complete');
        }
Dmitri R117
  • 2,502
  • 23
  • 20
0

I just ended up in returning as an empty object

'request': function request(config) {
    if(shouldCancelThisRequest){  
        return {};
    }
    return config;
}
jrswgtr
  • 2,287
  • 8
  • 23
  • 49
excitepv
  • 31
  • 6