1

When cancelling an http request like this:

$scope.runTest = function() {
    if (canceler) canceler.resolve();
    canceler = $q.defer();
    $http({
        method: 'GET',
        url: 'http://www.google.com/',
        timeout: canceler.promise
    })
    .success(function(data) {
        $scope.result.push({msg: "this won't be displayed on cancel"});
    })
    .error(function(data) {
        $scope.result.push({msg: "this will be displayed on cancel"});
    });
};

Is it possible to make the cancelled HTTP request have a specific HTTP code, like 205? It causes http interceptors to be triggered with http status 0, which is also used for timeouts or no network connection. I'd like to be able to differentiate between the two scenarios in the interceptors

Thanks!

2
  • the http status code should come from the server Commented Mar 30, 2015 at 22:11
  • @AvraamMavridis If you cancel the request before it completes, no. Commented Mar 30, 2015 at 22:15

2 Answers 2

7

I ended up with the following approach:

$scope.runTest = function() {

    if (canceler) {
        // Set non-zero status for http interceptors
        // Using 499, an nginx extension to flag cancelled http requests
        // Could be something else like a boolean, using status code for convenience
        canceler.promise.status = 499;

        // Cancel the request
        canceler.resolve();
    }

    canceler = $q.defer();
    $http({
        method: 'GET',
        url: 'http://www.google.com/',
        timeout: canceler.promise
    })
    .success(function(data) {
        // On sucesss
    })
    .error(function(data) {
        // On error
    });
};

Here I just set something on the timeout to flag the request as cancelled, as @Daniel Silva suggested. Then on my http interceptor:

app.config(function($httpProvider) {

    $httpProvider.interceptors.push(function($q) {
        return {
            'responseError': function(response) {

                var statusCode = response.status;

                // Get status from timeout, if 0 and timeout present
                if (statusCode === 0 && response.config.timeout) {
                    statusCode = response.config.timeout.status;
                }

                // Ignore client request cancelled
                if (statusCode === 499) {
                    return response;
                }

                // Reject via $q, otherwise the error will pass as success
                return $q.reject(response);
            }
        };
    });
});
Sign up to request clarification or add additional context in comments.

2 Comments

Can you let me know where to get the canceler object?
Add the $q service to your controller/directive/service, and call its defer() method. More info here
1

You need to keep in mind that the Angular $http timeout is a "client" timeout, though it has the same name of the server timeout. When you configure angular $http timeout, you are saying something like "I'll not wait till the server timeout". This can be specially useful when accessing a third party api, as you cannot configure timeout settings.

This is the reason for http status 0. There is no http 408 response because Angular cancels the request instead of waiting the server timeout.

You can handle the client timeout using the promise returned by $timeout service

var myTimeout = $timeout(function () {
    console.log("Cannot wait you anymore!");
}, 1000); 

$http({
    method: 'GET',
    url: 'http://www.google.com/',
    timeout: myTimeout
})
.success(function (data) {
    $scope.result.push({ msg: "this won't be displayed on cancel" });
})
.error(function (data) {
    $scope.result.push({ msg: "this will be displayed on cancel" });
});

3 Comments

Thank you very much for taking the time, but my problem is, how to make angular NOT use http status 0 for cancelled requests, if at all possible. Canceling the request is already accomplished in the code I posted, in my case not because of a client timeout, but because another request is performed, and I need to know which requests are cancelled in that manner. I guess I have to play around with the promise and see if I can resolve it with a different status.
Sure, @inolasco. I tried to explain that it'd be semantically incorrect to "override" the http status as if it was responded by the server. Angular uses http status 0 exactly to denote client cancelation. If you'd like to identify which request was canceled, you should give each request a promise (at the same way that you already do with success and error) because each request may require contextual success/error/cancelation handling.
Added sample code using your suggestion, for a complete answer.

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.