web-dev-qa-db-fra.com

Gestion des demandes annulées avec Express / Node.js et Angular

Lorsqu'une demande HTTP en attente est annulée par un client/navigateur, il semble que Node avec Express continue de traiter la demande. Pour les demandes intensives, le CPU est toujours occupé par des demandes inutiles.

Existe-t-il un moyen de demander à Node.js/Express de supprimer/arrêter ces demandes en attente dont l'annulation est demandée?

Cela devient particulièrement utile étant donné que les requêtes HTTP AngularJS 1.5 sont facilement annulables en appelant $cancelRequest() sur les objets $http/$resource.

De telles annulations peuvent se produire lors de l'exposition d'une méthode API fournissant des résultats pour les champs de saisie automatique ou de recherche: lors de la saisie dans le champ à compléter ou à saisir automatiquement, les demandes précédentes peuvent être annulées.

Un server.timeout Global ne résout pas le problème: 1) il s'agit a priori d'un paramètre global pour toutes les méthodes API exposées 2) le traitement en cours dans la demande annulée n'est pas supprimé.

22
Derek

reqobject injecté est livré avec les écouteurs .on().

L'écoute de l'événement close permet de gérer la fermeture de la connexion par le client (demande annulée par Angular ou, par exemple, l'utilisateur a fermé l'onglet de requête).

Voici 2 exemples simples sur l'utilisation de l'événement close pour arrêter le traitement des demandes.

Exemple 1: bloc synchrone annulable

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 */);
}

Exemple 2: bloc asynchrone annulable avec promesses (analogique à une réduction)

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

Avec express, vous pouvez essayer:

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