Обработка отмененного запроса с помощью 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;
Другие вопросы по тегам