Подтвердить что ты не робот

Обработка отмененного запроса с помощью Express/Node.js и Angular

Когда ожидающий HTTP-запрос отменяется клиентом/браузером, кажется, что Node с Express продолжает обрабатывать запрос. Для интенсивных запросов процессор все еще занят ненужными запросами.

Есть ли способ спросить Node.js/Express, чтобы убить/остановить эти ожидающие запросы, которые будут отменены?

Это становится особенно полезным, учитывая, что поскольку HTTP-запрос AngularJS 1.5 легко отменяется, вызывая $cancelRequest() on $http/$resource объекты.

Такие отмены могут возникать при экспонировании API-метода, предоставляющего результаты для полей автозаполнения или поиска: при вводе в поле для автозаполнения или ввода типа предыдущий запрос может быть отменен.

Глобальный server.timeout не решает проблему: 1) это априори глобальная настройка для всех открытых API-методов. 2) текущая обработка отмененного запроса не убивается.

4b9b3361

Ответ 1

Вложенный объект req отправляется с помощью прослушивателей .on().

Прослушивание события close позволяет обрабатывать, когда клиент закрывает соединение (запрос отменен Angular или, например, пользователь закрыл вкладку запросов).

Вот два простых примера, как использовать событие 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: Отменяемый асинхронный блок с promises (аналоговый снизу)

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();
}

Ответ 2

С помощью express вы можете попробовать:

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

Ответ 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;