angular-js: Set HTTP status code for cancelled req

2019-08-14 17:05发布

问题:

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!

回答1:

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


回答2:

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