Articles

Build and Understand Express Middleware through Examples

Posted on

Als je de afgelopen zeven of acht jaar veel aan Node hebt ontwikkeld, heb je Express waarschijnlijk wel eens gebruikt om een webserver te bouwen. Hoewel je een server in Node kunt maken zonder gebruik te maken van een library, geeft het je niet veel uit de doos en kan het behoorlijk omslachtig zijn om functionaliteit toe te voegen. Express is een minimalistische, “unopinionated” server library en is de de facto standaard geworden voor het bouwen van web apps in Node. Om Express te begrijpen, moet je Express Middleware begrijpen.

Wat is Express Middleware?

Middleware betekent letterlijk alles wat je tussen de ene en de andere laag van de software plaatst. Express middleware zijn functies die worden uitgevoerd tijdens de levenscyclus van een verzoek aan de Express server. Elke middleware heeft toegang tot de HTTP request en response voor elke route (of pad) waaraan het is gekoppeld. In feite is Express zelf volledig gecompromitteerd uit middleware functies. Bovendien kan middleware het HTTP verzoek beëindigen of doorgeven aan een andere middleware functie door gebruik te maken van next (meer daarover binnenkort). Deze “chaining” van middleware stelt u in staat om uw code te compartimenteren en herbruikbare middleware te maken.

In dit artikel leg ik uit wat middleware is, waarom u het zou gebruiken, hoe u bestaande Express middleware kunt gebruiken, en hoe u uw eigen middleware voor Express kunt schrijven.

Eisen om Express Middleware te schrijven

Er zijn een paar dingen die u geïnstalleerd moet hebben om Express middleware te maken, te gebruiken en te testen. Ten eerste, heb je Node en NPM nodig. Om er zeker van te zijn dat u deze hebt geïnstalleerd, kunt u het volgende uitvoeren:

npm -v && node -v

U zou de Node- en NPM-versies moeten zien die u hebt geïnstalleerd. Als u een foutmelding krijgt, moet u Node installeren. Ik gebruik de laatste versie van beide op het moment van dit artikel, dat is Node 10.9.0 en NPM 6.4.1, maar alle voorbeelden zouden moeten werken met Node versies 8+ en NPM versies 5+.

Ik gebruik ook Express versie 4.x. Dit is belangrijk omdat er grote veranderingen zijn doorgevoerd van versie 3.x naar 4.x.

Het zal ook nuttig zijn om Postman geïnstalleerd te hebben om routes te testen die andere HTTP werkwoorden gebruiken dan GET.

Express Middleware: De basis

Om te beginnen, zult u de meest eenvoudige van Express’s ingebouwde middleware gebruiken. Dit geeft je de kans om te zien hoe middleware wordt gebruikt, en hoe Express middleware is gestructureerd.

Maak een nieuw project aan en npm init het…

npm initnpm install express --save

Maak server.js en plak de volgende code:

const express = require('express');const app = express();app.get('/', (req, res, next) => { res.send('Welcome Home');});app.listen(3000);

Run de server via node server.js, open http://localhost:3000, en u zou “Welcome Home” in uw browser moeten zien afgedrukt.

De app.get() functie is Middleware op applicatieniveau. U zult zien dat de parameters die aan de methode worden doorgegeven reqres, en next zijn. Dit zijn het inkomende verzoek, het antwoord dat wordt geschreven, en een methode die moet worden aangeroepen om het verzoek door te geven aan de volgende middleware functie zodra de huidige middleware klaar is. In dit geval, zodra het antwoord is verzonden, verlaat de functie. Je zou hier ook andere middleware kunnen ketenen door de next() methode aan te roepen.

Laten we eens kijken naar nog een paar voorbeelden van de verschillende soorten middleware.

Express Request Logging Middleware Voorbeeld

In Express kun je middleware instellen als “globale” middleware; dat wil zeggen dat deze wordt aangeroepen voor elk inkomend verzoek.

Verander de inhoud van server.js in:

const express = require('express');const app = express();app.use((req, res, next) => { console.log(req); next();});app.get('/', (req, res, next) => { res.send('Welcome Home');});app.listen(3000);

Dit keer zou je, als je naar http://localhost:3000 gaat, hetzelfde moeten zien in je browservenster, maar terug in het consolevenster zie je de uitvoer van het inkomende request-object.

De middleware logt het request object uit en roept dan next() aan. De volgende middleware in de pijplijn handelt het get request naar de root URL af en stuurt het tekst antwoord terug. Het gebruik van app.use() betekent dat deze middleware bij elke aanroep van de toepassing wordt aangeroepen.

Restrict Express Request Content Type Voorbeeld

Naast het uitvoeren van middleware voor alle aanroepen, kunt u ook aangeven om alleen middleware voor specifieke aanroepen uit te voeren.

Wijzig het server.js bestand opnieuw in:

const express = require('express');const app = express();const requireJsonContent = () => { return (req, res, next) => { if (req.headers !== 'application/json') { res.status(400).send('Server requires application/json') } else { next() } }}app.get('/', (req, res, next) => { res.send('Welcome Home');});app.post('/', requireJsonContent(), (req, res, next) => { res.send('You sent JSON');})app.listen(3000);

Deze keer start u de server door het volgende uit te voeren:

node server.js

Om dit te testen, opent u Postman en maakt u een postverzoek aan http://localhost:3000. Stel geen headers in en voer het verzoek uit. U krijgt de melding “Server requires application/json”.

Nu gaat u terug en voegt u de Content-Type header toe met een waarde van application/json en voert u het verzoek opnieuw uit. U krijgt het bericht “U heeft JSON verzonden” terug van de server.

Deze app.post() method call voegt de requireJsonContent() middleware functie toe om er zeker van te zijn dat de inkomende request payload een Content-Type header waarde heeft die is ingesteld op application/json. Als de header niet door de controle komt, wordt een foutmelding gestuurd. Zo ja, dan wordt het verzoek doorgegeven aan het volgende stuk middleware in de keten via de next() methode.

Third-Party Express Middleware

Je hebt tot nu toe een paar middlewares op maat gebouwd, maar er zijn al veel pakketten die de dingen doen die je normaal gesproken zou willen doen. In feite heb je de eenvoudige routing middleware bibliotheek gebruikt door gebruik te maken van de app.get() of app.post() middleware functies. Er zijn duizenden middleware bibliotheken voor het doen van dingen als parsing van inkomende gegevens, routing, en autorisatie.

Okta heeft een Express middleware voor OIDC beveiliging die ik je zal laten zien om het gebruik van middleware bibliotheken van derden te demonstreren.

Waarom Okta voor Express Applicaties

Bij Okta is het ons doel om identiteitsbeheer een stuk eenvoudiger, veiliger, en schaalbaarder te maken dan wat je gewend bent. Okta is een cloudservice waarmee ontwikkelaars gebruikersaccounts en gebruikersaccountgegevens kunnen aanmaken, bewerken en veilig opslaan, en deze kunnen koppelen aan een of meerdere applicaties. Met onze API kunt u:

  • authenticeren en autoriseren van uw gebruikers
  • gegevens over uw gebruikers opslaan
  • op basis van een wachtwoord en sociaal inloggen
  • uw applicatie beveiligen met multifactorauthenticatie
  • En nog veel meer! Bekijk onze productdocumentatie

Okta’s OIDC Express Middleware

Om Okta’s OIDC middleware voor Express te installeren, voert u het volgende uit:

npm install @okta/[email protected] --save

In het server.js-bestand maakt u een instantie als de middleware met enkele configuratieopties, zodat Okta weet hoe het verbinding moet maken met uw Okta-applicatie.

const oidc = new ExpressOIDC({ issuer: 'https://{yourOktaDomain}/oauth2/default', client_id: '{yourClientId}', client_secret: '{yourClientSecret}', redirect_uri: 'http://localhost:3000/authorization-code/callback', scope: 'openid profile'});

U moet Express ook vertellen dat het de OIDC-middleware-router moet gebruiken in plaats van de standaardrouter.

app.use(oidc.router);

Dan gebruikt u het net als elke andere middleware:

app.get('/protected', oidc.ensureAuthenticated(), (req, res) => { res.send('Top Secret');});

De oidc.ensureAuthenticated()-functie is een middleware in de Okta-bibliotheek. Het voert een functie uit om te zien of de huidige gebruiker is ingelogd. Als dat zo is, roept het next() aan om de app.get() functie door te laten gaan met het afhandelen van het verzoek. Als dat niet het geval is, wordt een HTTP 401 (Unauthorized) antwoord teruggestuurd.

De volgorde van middleware is belangrijk

Als Express een verzoek ontvangt, wordt elke middleware die overeenkomt met het verzoek uitgevoerd in de volgorde waarin deze is geïnitialiseerd, totdat er een afsluitende actie is (zoals een antwoord dat wordt verzonden).

Middleware Flow

Dus als er een fout optreedt, wordt alle middleware die bedoeld is om fouten af te handelen, in volgorde aangeroepen totdat een van hen de next() functie-oproep niet aanroept.

Foutafhandeling in Express Middleware

Express heeft een ingebouwde standaard foutafhandeling die aan het eind van de middleware pijplijn wordt ingevoegd en die alle niet-afgehandelde fouten afhandelt die mogelijk in de pijplijn zijn opgetreden. De handtekening voegt een error parameter toe aan de standaard parameters van request, response, en next. De basishandtekening ziet er als volgt uit:

app.use((err, req, res, next) => { // middleware functionality here})

Om een foutafhandelende middleware op te roepen, geeft u de fout gewoon door aan next(), op deze manier:

app.get('/my-other-thing', (req, res, next) => { next(new Error('I am passing you an error!'));});app.use((err, req, res, next) => { console.log(err); if(!res.headersSent){ res.status(500).send(err.message); }});

In dit geval zal de middleware voor foutafhandeling aan het einde van de pijplijn de fout afhandelen. U ziet misschien ook dat ik de eigenschap res.headersSent heb gecontroleerd. Dit controleert alleen of het antwoord de headers al naar de client heeft gestuurd. Als dat niet het geval is, stuurt het een 500 HTTP status en de foutmelding naar de client. Je kunt ook fout afhandelende middleware ketenen. Dit is gebruikelijk om verschillende soorten fouten op verschillende manieren af te handelen. Bijvoorbeeld:

app.get('/nonexistant', (req, res, next) => { let err = new Error('I couldn\'t find it.'); err.httpStatusCode = 404; next(err);});app.get('/problematic', (req, res, next) => { let err = new Error('I\'m sorry, you can\'t do that, Dave.'); err.httpStatusCode = 304; next(err);});// handles not found errorsapp.use((err, req, res, next) => { if (err.httpStatusCode === 404) { res.status(400).render('NotFound'); } next(err);});// handles unauthorized errorsapp.use((err, req, res, next) => { if(err.httpStatusCode === 304){ res.status(304).render('Unauthorized'); } next(err);})// catch allapp.use((err, req, res, next) => { console.log(err); if (!res.headersSent) { res.status(err.httpStatusCode || 500).render('UnknownError'); }});

In dit geval controleert de middleware of er een 404-fout (niet gevonden) is gegooid. Als dat het geval is, wordt de sjabloonpagina ‘NotFound’ weergegeven en wordt de fout doorgegeven aan het volgende onderdeel van de middleware. De volgende middleware controleert of er een 304 (unauthorized) foutmelding is gegeven. Als dat het geval was, rendert hij de ‘Unauthorized’ pagina, en geeft de fout door aan de volgende middleware in de pijplijn. Tenslotte logt de “catch all” error handler gewoon de fout en als er geen response is verstuurd, stuurt het de fout httpStatusCode (of een HTTP 500 status als er geen is verstrekt) en rendert het ‘UnknownError’ template.

Learn More About Express Middleware

Voor gedetailleerde instructies over het opzetten van de Okta OIDC middleware, kunt u de ExpressJS Quickstart volgen.

Er is ook een lijst van officieel ondersteunde Express middleware in deze GitHub repo die je kunt uitproberen en uitproberen om meer te leren

Ten slotte, als je geïnteresseerd bent om meer te leren over hoe je Okta kunt gebruiken, er is een Okta Node SDK voor het implementeren van meer gebruikersbeheer functionaliteit in je applicatie.

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *