Come faccio a chiudere a livello di codice un'istanza di ExpressJS per il test?


106

Sto cercando di capire come chiudere un'istanza di Express. Fondamentalmente, voglio l'inverso della .listen(port)chiamata: come faccio a far smettere di ascoltare un server Express, rilasciare la porta e spegnerlo in modo pulito?

So che sembra che potrebbe essere una query strana, quindi ecco il contesto; forse c'è un altro modo per affrontare questo problema e ci sto pensando nel modo sbagliato. Sto cercando di configurare un framework di test per la mia app socket.io/nodejs. È un'app a pagina singola, quindi nei miei script di test (sto usando Mocha, ma non ha importanza) Voglio essere in grado di avviare il server, eseguire test su di esso e quindi spegnere il server. Posso aggirare il problema assumendo che il server sia acceso prima dell'inizio del test o facendo in modo che uno dei test avvii il server e che ogni test successivo presuma che sia attivo, ma è davvero complicato. Preferirei di gran lunga che ogni file di test avvii un'istanza del server con le impostazioni appropriate e quindi chiudesse quell'istanza al termine dei test. Ciò significa che non ci sono strane dipendenze nell'esecuzione del test e tutto è pulito. Significa anche che posso eseguire test di avvio / arresto.

Quindi, qualche consiglio su come farlo? Ho pensato di attivare manualmente le eccezioni per disattivarlo, ma sembra complicato. Ho esaminato la documentazione e la fonte di Express, ma non riesco a trovare alcun metodo che arresti il ​​server. Potrebbe anche esserci qualcosa in socket.io per questo, ma poiché il server socket è solo collegato al server Express, penso che ciò debba accadere al livello Express.

Risposte:


156

Le cose sono cambiate perché il server express non eredita più dal server http del nodo. Fortunatamente, app.listen restituisce l'istanza del server.

var server = app.listen(3000);

// listen for an event
var handler = function() {
  server.close();
};

23
Nel caso del test Mocha, dove si richiede ('app') estendo l'oggetto app: app.server = app.listen (3000); quindi più tardi posso dire: var app = require ('./ app'); app.server.close ();
Jack Chi

2
durante il test del server, controlla github.com/visionmedia/supertest che ti consentirà di testare senza avviare il server effettivo
Lukas Liesis

Suggerirei anche di passare la richiamata eseguita a server.close()se la si chiama da un hook.
Ullauri

Nota: esiste una grande differenza tra "app", che è l'istanza dell'applicazione Express, e il valore restituito di "app.listen", che è l'istanza del server HTTP nativo sottostante che ha il metodo "close". @JackChi ha accennato a questo sopra.
Ajxs

Ciò non causa problemi con i socket client aperti che vengono lasciati aperti?
Cameron Tacklind

18

Usa app.close(). Esempio completo:

var app = require('express').createServer();
app.get('/', function(req, res){
  res.send('hello world');
});
app.get('/quit', function(req,res) {
  res.send('closing..');
  app.close();
});
app.listen(3000);

Chiamata app.close()all'interno della richiamata quando i test sono terminati. Ma ricorda che il processo è ancora in esecuzione (sebbene non sia più in ascolto).

Se dopo questo, devi terminare il processo, chiama process.exit(0).

Collegamenti:

app.close: http://nodejs.org/docs/latest/api/http.html#server.close (lo stesso vale per)

process.exit: http://nodejs.org/docs/latest/api/process.html#process.exit


1
Perfetto, esattamente quello che stavo cercando. Immagino di non averlo trovato in Express perché stavano estendendo il server http del nodo principale, che non ho capito completamente. Grazie!
drewww

Grazie Srijan, anche questo ha aiutato me
Adam Hopkinson

È ancora vero? express.createServer è contrassegnato come obsoleto e restituisce un errore che indica che l'app non eredita più dal server http.js
Frank Schwieterman

4
Questo non è valido da express 3.
gprasant

4
Esporre un URL per chiudere un server come questo non è una buona idea IMHO.
shime

2

Ho risposto a una variazione di "come terminare un server HTTP" molte volte su diversi canali di supporto. Sfortunatamente, non potrei raccomandare nessuna delle librerie esistenti perché mancano in un modo o nell'altro. Da allora ho messo insieme un pacchetto che (credo) stia gestendo tutti i casi previsti per una graziosa terminazione del server HTTP.

https://github.com/gajus/http-terminator

Il vantaggio principale di http-terminator è che:

  • non esegue la patch di scimmia Node.js API
  • distrugge immediatamente tutti i socket senza una richiesta HTTP allegata
  • consente un grazioso timeout ai socket con richieste HTTP in corso
  • gestisce correttamente le connessioni HTTPS
  • informa le connessioni utilizzando keep-alive che il server si sta spegnendo impostando una connessione: close header
  • non termina il processo Node.js.

Utilizzo con Express.js:

import express from 'express';
import {
  createHttpTerminator,
} from 'http-terminator';

const app = express();

const server = app.listen();

const httpTerminator = createHttpTerminator({
  server,
});

await httpTerminator.terminate();


-1

Puoi farlo facilmente scrivendo uno script bash per avviare il server, eseguire i test e arrestare il server. Questo ha il vantaggio di consentirti di creare un alias per quello script per eseguire tutti i tuoi test rapidamente e facilmente.

Utilizzo tali script per l'intero processo di distribuzione continua. Dovresti guardare Dead Simple Git Workflow di Jon Rohan per alcuni approfondimenti su questo.


2
Funzionerebbe, ma preferirei una soluzione senza bash, se possibile. Forse è una preferenza stupida, ma mi piacerebbe avviare / arrestare il server dal contesto di test perché rende più facile scrivere test specifici per la configurazione del server + test di avvio / arresto. Inoltre, non introduce l'indicazione indiretta di dover eseguire test relativi al server tramite uno script separato.
drewww

Perché stai scrivendo test specifici per l'ambiente? Forse mi sbaglio, ma questo mi sembra una cattiva pratica. Proverei a rimanere indipendente dall'ambiente con i tuoi test, poiché vorresti che i tuoi test funzionassero in tutto il tuo team indipendentemente dal loro ambiente di sviluppo.
Josh Smith

Non sto facendo nulla di specifico per l'ambiente qui, non credo. Ci saranno una manciata di diverse opzioni di avvio per il server (come leggere le opzioni di configurazione da un file, caricare lo stato da un datastore, ecc.) Che sarebbe bello testare nello stesso framework in cui provo tutto il resto. Mi piacerebbe anche fare dei test che, ad esempio, chiudano il server, lo riaccendano e si assicurino che non abbia perso lo stato durante il processo. È più facile se posso farlo a livello di codice dal nodo che avere anche il codice di test in bash.
drewww

Non inseriresti il ​​codice di test in bash stesso. Dovresti semplicemente avviare il server ed eseguire i test dallo script, proprio come faresti tu stesso sulla riga di comando. Non c'è una vera magia speciale lì.
Josh Smith
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.