2016-02-04 8 views
13

Quando una richiesta HTTP in attesa viene annullata da un client/browser, sembra che il nodo con Express continui a elaborare la richiesta. Per richieste intensive, la CPU è ancora impegnata con richieste non necessarie.Gestione della richiesta annullata con Express/Node.js e Angular

C'è un modo per chiedere a Node.js/Express di eliminare/interrompere queste richieste in sospeso che devono essere annullate?

Diviene particolarmente utile dato che poiché AngularJS richiesta HTTP 1.5 sono facilmente cancellable chiamando $cancelRequest() su $http/$resource oggetti.

Tali annullamenti possono verificarsi quando si espone un metodo API che fornisce risultati per i campi di completamento automatico o di ricerca: quando si digita il campo per essere completato automaticamente o digitato, è possibile annullare le richieste precedenti.

Un globale server.timeout non risolve il problema: 1) è a priori un'impostazione globale per tutti i metodi API esposti 2) l'elaborazione in corso nella richiesta annullata non viene interrotta.

risposta

9

iniettata req oggetto viene fornito con gli ascoltatori .on().

L'ascolto dell'evento close consente di gestire quando il client chiude la connessione (richiesta annullata da Angular o, ad esempio, l'utente ha chiuso la scheda di query).

Ecco due semplici esempi su come utilizzare l'evento close per interrompere l'elaborazione della richiesta.

Esempio 1: blocco sincrono Cancellable

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

Esempio 2: blocco asincrono Cancellable con promesse (analogico ad un ridurre)

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

Potresti voler ascoltare "" abortito "' invece di '" chiudi "'. https://nodejs.org/api/http.html#http_event_aborted – ZachB

0

È possibile impostare un timeout per le richieste sul server:

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; 
+0

Desidero annullare una richiesta non appena il client chiede di annullarla. Utile con le query per il completamento automatico. – Derek

+0

Ho aggiunto alcuni commenti nella domanda su questa situazione: Un server.timeout globale non risolve il problema: 1) è a priori un'impostazione globale per tutti i metodi API esposti 2) l'elaborazione in corso nella richiesta annullata non viene uccisa . – Derek

+0

Grazie. Lo esaminerò. – gnerkus

4

Con espresso, si può provare:

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