2013-06-16 17 views
18

So che il nodo non è bloccante, ma mi sono appena reso conto che il comportamento predefinito di http.listen(8000) significa che tutte le richieste HTTP vengono gestite una alla volta. So che non dovrei essere sorpreso da questo (è come funzionano le porte), ma mi fa seriamente chiedermi come scrivere il mio codice in modo da poter gestire più richieste HTTP parallele.Gestione di più richieste HTTP parallele in Node.js

Quindi qual è il modo migliore di scrivere un server in modo che non entri sulla porta 80 e le risposte di lunga durata non comportino lunghe code di richieste?

Per illustrare il problema, provare a eseguire il codice riportato di seguito e caricarlo in due schede del browser contemporaneamente.

var http = require('http'); 
http.createServer(function (req, res) { 
    res.setHeader('Content-Type', 'text/html; charset=utf-8'); 
    res.write("<p>" + new Date().toString() + ": starting response"); 
    setTimeout(function() { 
     res.write("<p>" + new Date().toString() + ": completing response and closing connection</p>"); 
     res.end(); 
    }, 4000); 
}).listen(8080); 
+1

http://blog.mixu.net/2011/02/01/understanding-the-node-js-event-loop/ – Paul

risposta

14

Si sta fraintendendo il funzionamento del nodo. Il codice sopra può accettare connessioni TCP da centinaia o migliaia di client, leggere le richieste HTTP, quindi attendere il timeout di 4000 ms in cui ci si è immessi, quindi inviare le risposte. Ogni cliente riceverà una risposta in circa 4000 + un piccolo numero di millisecondi. Durante quel setTimeout (e durante qualsiasi operazione di I/O) il nodo può continuare l'elaborazione. Ciò include l'accettazione di ulteriori connessioni TCP. Ho testato il tuo codice e ognuno ha una risposta in 4 secondi. Il secondo NON prende 8, se è così che pensi che funzioni.

io corsi curl -s localhost:8080 in 4 schede come rapidamente possibile tramite la tastiera e il secondo nei codici di tempo sono:

  1. 54 a 58
  2. 54 a 58
  3. 55 a 59

Non c'è alcun problema qui, anche se posso capire come si potrebbe pensare che ce ne sia uno. Il nodo sarebbe completamente rotto se funzionasse come suggerito dal tuo post.

Ecco un altro modo per verificare:

for i in 1 2 3 4 5 6 7 8 9 10; do curl -s localhost:8080 &;done                                          
+5

Sei corretto. È Chrome che lo sta facendo. Almeno per me, la seconda richiesta non verrà emessa fino a quando non viene restituito il primo. – Andrew

+0

Anche Chrome dovrebbe consentire normalmente fino a 6 connessioni simultanee per origine. –

+1

Lo so. Ecco perché sono rimasto sorpreso e ho pensato che fosse Nodo. – Andrew

3

Il codice può accettare più connessioni, perché il lavoro è fatto in funzione di callback della chiamata setTimeout.

Ma se invece di setTimeout fai un lavoro pesante ... allora è vero che node.js non accetterà altre connessioni multiple! SetTimeout libera accidentalmente il processo in modo che node.js possa accettare altri lavori e il codice venga eseguito in un altro "thread".

Non so quale sia il modo corretto di implementarlo. Ma è così che sembra funzionare.

0

Ho usato codice seguente per verificare richiesta movimentazione

app.get('/', function(req, res) { 
    console.log('time', MOMENT()); 
    setTimeout(function() { 
    console.log(data, '   ', MOMENT()); 
    res.send(data); 
    data = 'changing'; 
    }, 50000); 
    var data = 'change first'; 
    console.log(data); 
}); 

Poiché tale richiesta non richiede tempo di elaborazione molto, tranne per 50 sec di setTimeout e tutto il time-out sono stati trattati insieme come al solito.

Risposta 3 richiesta insieme-

time moment("2017-05-22T16:47:28.893") 
change first 
time moment("2017-05-22T16:47:30.981") 
change first 
time moment("2017-05-22T16:47:33.463") 
change first 
change first   moment("2017-05-22T16:48:18.923") 
change first   moment("2017-05-22T16:48:20.988") 
change first   moment("2017-05-22T16:48:23.466") 

Dopo questo mi sono trasferito a seconda fase ... vale a dire, che cosa succede se la mia richiesta vuole così tanto tempo per elaborare un file di sincronizzazione o di qualche altra cosa che prendere tempo.

app.get('/second', function(req, res) { 
    console.log(data); 
    if(req.headers.data === '9') { 
     res.status(200); 
     res.send('response from api'); 
    } else { 
     console.log(MOMENT()); 
     for(i = 0; i<9999999999; i++){} 
     console.log('Second MOMENT', MOMENT()); 
     res.status(400); 
     res.send('wrong data'); 
    } 

    var data = 'second test'; 
}); 

Come la mia prima richiesta era ancora in corso quindi il mio secondo non ha ottenuto accettato da Node. Così mi sono seguente risposta di 2 richiesta-

undefined 
moment("2017-05-22T17:43:59.159") 
Second MOMENT moment("2017-05-22T17:44:40.609") 
undefined 
moment("2017-05-22T17:44:40.614") 
Second MOMENT moment("2017-05-22T17:45:24.643") 

Così per tutte le funzioni asincrone theres un filo virtuale in Node e Nodo non accetta altra richiesta prima di completare le richieste precedenti asincrona funzionano come (fs, mysql, o chiamando API), tuttavia si mantiene autonomo come thread singolo e non elabora altre richieste fino a quando tutte le precedenti non sono state completate.

1

Il browser blocca le altre stesse richieste. Se lo chiami da diversi browser, questo funzionerà in modo parallelo.

Problemi correlati