使用$ http拦截器取消请求?

时间:2014-02-28 09:13:51

标签: angularjs

我试图找出是否可以使用$http拦截器在请求发生之前取消请求。

  

有一个触发请求的按钮,但如果用户双击它,我不希望同一个请求被触发两次。

现在,我意识到有几种方法可以解决这个问题,我们已经有了一个可行的解决方案,我们将$http包装在一个服务中,该服务跟踪当前待处理的请求,并简单地忽略新的请求。相同的方法,网址和数据。

基本上这是我试图用拦截器做的行为:

factory('httpService', ['$http', function($http) {

    var pendingCalls = {};

    var createKey = function(url, data, method) {
        return method + url + JSON.stringify(data);
    };

    var send = function(url, data, method) {
        var key = createKey(url, data, method);
        if (pendingCalls[key]) {
            return pendingCalls[key];
        }
        var promise = $http({
            method: method,
            url: url,
            data: data
        });
        pendingCalls[key] = promise;
        promise.finally(function() {
            delete pendingCalls[key];
        });
        return promise;
    };

    return {
        post: function(url, data) {
            return send(url, data, 'POST');
        }
    }

}])

当我查看$http拦截器的API时,它似乎不是实现此目的的一种方法。我可以访问config对象,但这是关于它的。

我是否试图超越拦截器可以在这里使用的界限,还是有办法实现?

2 个答案:

答案 0 :(得分:1)

根据$http documentation,您可以从请求拦截器返回自己的配置。

尝试这样的事情:

config(function($httpProvider) {
    var cache = {};

    $httpProvider.interceptors.push(function() {
        return {
            response : function(config) {
                var key = createKey(config);
                var cached = cache[key];
                return cached ? cached : cached[key];    
            }
        }
    });
}

答案 1 :(得分:0)

很老的问题,但我会给出一个机会来处理这种情况。

如果我理解正确,你会尝试:

1 - 发起请求并注册一些内容以引用它;

2 - 如果发生了另一个请求,则要检索该第一个引用并将请求放入同一端点。

这可能由$http配置对象中的请求超时处理。在拦截器上,您可以验证它是否在当前请求中注册了一个,如果没有,您可以设置一个,保留对它的引用并在之后处理:

function DropoutInterceptor($injector) {
    var $q = $q || $injector.get('$q');
    var dropouts = {};

    return {
        'request': function(config) {
            // I'm using the request's URL here to make
            // this reference, but this can be bad for
            // some situations.
            if (dropouts.hasOwnProperty(config.url)) {
                // Drop the request
                dropouts[config.url].resolve();
            }

            dropouts[config.url] = $q.defer();

            // If the request already have one timeout
            // defined, keep it, othwerwise, set up ours.
            config.timeout = config.timeout || dropouts[config.url];

            return config;
        },
        'requestError': function(reason) {
            delete dropouts[reason.config.url];

            return $q.reject(reason);
        },
        'response': function(response) {
            delete dropouts[response.config.url];

            return response;
        },
        'responseError': function(reason) {
            delete dropouts[reason.config.url];

            return $q.reject(reason);
        }
    };
}