【问题标题】:Handling cancelled request with Express/Node.js and Angular使用 Express/Node.js 和 Angular 处理取消的请求
【发布时间】:2016-05-13 21:34:29
【问题描述】:

当客户端/浏览器取消挂起的 HTTP 请求时,Node with Express 似乎会继续处理该请求。对于密集的请求,CPU 仍然忙于处理不必要的请求。

有没有办法让 Node.js/Express 终止/停止这些请求取消的待处理请求?

鉴于 AngularJS 1.5 HTTP 请求很容易通过在 $http/$resource 对象上调用 $cancelRequest() 来实现 cancellable,因此它变得特别有用。

当公开为自动完成或搜索字段提供结果的 API 方法时,可能会发生这种取消:在要自动完成或预先输入的字段中键入时,可以取消先前的请求。

全局 server.timeout 不能解决问题:1) 它是所有公开 API 方法的先验全局设置 2) 取消请求中正在进行的处理不会被终止。

【问题讨论】:

    标签: javascript angularjs node.js express request-cancelling


    【解决方案1】:

    用express,你可以试试:

    req.connection.on('close',function(){    
      // code to handle connection abort
      console.log('user cancelled');
    });
    

    【讨论】:

    • connection/socket和request有很大区别。监听连接关闭可能是一个(大)错误(尽管在测试中一切都会正常工作) - 大多数浏览器保持连接打开,尽管请求本身已完成(请参阅“连接:保持活动”标头或 HTTP 持久连接术语) ,因此其他请求可以使用相同的底层连接。
    【解决方案2】:

    注入的reqobject 与侦听器.on() 一起提供。

    侦听close 事件允许在客户端关闭连接时进行处理(请求被 Angular 取消,或者,例如,用户关闭了查询选项卡)。

    这里有两个简单的例子,如何使用closeevent 来停止请求处理。

    示例一:可取消同步块

    var clientCancelledRequest = 'clientCancelledRequest';
    
    function cancellableAPIMethodA(req, res, next) {
        var cancelRequest = false;
    
        req.on('close', function (err){
           cancelRequest = true;
        });
    
        var superLargeArray = [/* ... */];
    
        try {
            // Long processing loop
            superLargeArray.forEach(function (item) {
                    if (cancelRequest) {
                        throw {type: clientCancelledRequest};
                    }
                    /* Work on item */
            });
    
            // Job done before client cancelled the request, send result to client
            res.send(/* results */);
        } catch (e) {
            // Re-throw (or call next(e)) on non-cancellation exception
            if (e.type !== clientCancelledRequest) {
                throw e;
            }
        }
    
        // Job done before client cancelled the request, send result to client
        res.send(/* results */);
    }
    

    示例 2:带有 promise 的可取消异步块(类似于 reduce)

    function cancellableAPIMethodA(req, res, next) {
        var cancelRequest = false;
    
        req.on('close', function (err){
           cancelRequest = true;
        });
    
        var superLargeArray = [/* ... */];
    
        var promise = Q.when();
        superLargeArray.forEach(function (item) {
                promise = promise.then(function() {
                    if (cancelRequest) {
                        throw {type: clientCancelledRequest};
                    } 
                    /* Work on item */ 
                });
        });
    
        promise.then(function() {
            // Job done before client cancelled the request, send result to client
            res.send(/* results */);
        })
        .catch(function(err) {
            // Re-throw (or call next(err)) on non-cancellation exception
            if (err.type !== clientCancelledRequest) {
                throw err;
            }
        })
        .done();
    }
    

    【讨论】:

    【解决方案3】:

    您可以为服务器上的请求设置timeout

    var server = app.listen(app.get('port'), function() {
      debug('Express server listening on port ' + server.address().port);
    });
    // Set the timeout for a request to 1sec
    server.timeout = 1000;
    

    【讨论】:

    • 我想在客户要求取消时立即取消请求。对自动完成查询很有用。
    • 我在关于这种情况的问题中添加了一些 cmets:全局 server.timeout 不能解决问题:1)它是所有公开 API 方法的先验全局设置 2)正在进行的处理在取消的请求中不会被杀死。
    • 谢谢。我会调查的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-29
    • 2023-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多