使用 Express/Node.js 和 Angular 处理取消的请求
Handling cancelled request with Express/Node.js and Angular
当挂起的 HTTP 请求被 client/browser 取消时,Node with Express 似乎会继续处理该请求。对于密集请求,CPU 仍然忙于处理不必要的请求。
有没有办法让 Node.js/Express 去 kill/stop 这些请求取消的未决请求?
它变得特别有用,因为 AngularJS 1.5 HTTP 请求很容易 cancellable 通过在 $http
/$resource
对象上调用 $cancelRequest()
。
公开为自动完成或搜索字段提供结果的 API 方法时可能会发生此类取消:在要自动完成或提前输入的字段中键入时,可以取消先前的请求。
全局server.timeout
没有解决问题:1)它是所有暴露的API方法的先验全局设置2)取消请求中正在进行的处理不会被终止。
您可以为服务器上的请求设置 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;
已注入 req
对象随侦听器一起提供 .on()
。
侦听 close
事件允许在客户端关闭连接时进行处理(请求被 Angular 取消,或者,例如,用户关闭了查询选项卡)。
这里有 2 个简单示例,说明如何使用 close
事件停止请求处理。
例1:可取消同步块
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();
}
有快递的,可以试试:
req.connection.on('close',function(){
// code to handle connection abort
console.log('user cancelled');
});
当挂起的 HTTP 请求被 client/browser 取消时,Node with Express 似乎会继续处理该请求。对于密集请求,CPU 仍然忙于处理不必要的请求。
有没有办法让 Node.js/Express 去 kill/stop 这些请求取消的未决请求?
它变得特别有用,因为 AngularJS 1.5 HTTP 请求很容易 cancellable 通过在 $http
/$resource
对象上调用 $cancelRequest()
。
公开为自动完成或搜索字段提供结果的 API 方法时可能会发生此类取消:在要自动完成或提前输入的字段中键入时,可以取消先前的请求。
全局server.timeout
没有解决问题:1)它是所有暴露的API方法的先验全局设置2)取消请求中正在进行的处理不会被终止。
您可以为服务器上的请求设置 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;
已注入 req
对象随侦听器一起提供 .on()
。
侦听 close
事件允许在客户端关闭连接时进行处理(请求被 Angular 取消,或者,例如,用户关闭了查询选项卡)。
这里有 2 个简单示例,说明如何使用 close
事件停止请求处理。
例1:可取消同步块
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();
}
有快递的,可以试试:
req.connection.on('close',function(){
// code to handle connection abort
console.log('user cancelled');
});