Обработка отмененного запроса с помощью Express/Node.js и Angular
Когда клиент / браузер отменяет ожидающий HTTP-запрос, кажется, что Node с Express продолжает обрабатывать запрос. Для интенсивных запросов процессор все еще занят ненужными запросами.
Есть ли способ попросить Node.js/Express убить / остановить эти ожидающие запросы, которые должны быть отменены?
Это становится особенно полезным, учитывая, что, поскольку HTTP-запрос AngularJS 1.5 легко отменяется путем вызова $cancelRequest()
на $http
/$resource
объекты.
Такие отмены могут возникать при представлении метода API, предоставляющего результаты для автозаполнения или полей поиска: при вводе в поле для автозаполнения или ввода текста предыдущий запрос может быть отменен.
Глобальный server.timeout
не решает проблему: 1) это априори глобальная настройка для всех открытых методов API 2) текущая обработка отмененного запроса не прекращается.
3 ответа
Введенный 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. Отменяемый асинхронный блок с обещаниями (аналог редуцирования)
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');
});
Вы можете установить тайм-аут для запросов на вашем сервере:
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;