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é.
req
object 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();
}
Avec express, vous pouvez essayer:
req.connection.on('close',function(){
// code to handle connection abort
console.log('user cancelled');
});