Introductie
Uitzonderingen en fouten zullen zich ongetwijfeld voordoen wanneer gebruikers met een applicatie omgaan. Het is aan de software-engineers om een manier te kiezen om eventuele fouten op te lossen - bewust of onbewust. Als gevolg hiervan moeten backend-ontwikkelaars die API's met Express bouwen, ervoor zorgen dat ze een nuttige, efficiënte en bruikbare API bouwen. Het is van het grootste belang om fouten op een zodanige manier af te handelen dat een robuust systeem wordt gebouwd, omdat dit helpt om ontwikkeltijd, regelrechte fouten, productiviteitsproblemen te verminderen en het succes of de schaalbaarheid van softwareontwikkeling bepaalt.
Moet u het foutbericht loggen, de fout onderdrukken, gebruikers op de hoogte stellen van de fout of code schrijven om fouten af te handelen? Vraag me niet meer af.
In deze handleiding leren we hoe we een robuuste codebase voor foutafhandeling kunnen bouwen voor Express-applicaties, die zal helpen bij het detecteren van applicatiefouten en het ondernemen van optimale acties om elke applicatie te herstellen van een probleemloze storing tijdens runtime.
Opmerking: We zullen Postman gebruiken om de API in onze demo te testen. Je kunt het downloaden op de Postbode Download pagina. U kunt ook gewoon de browser gebruiken, de opdrachtregel curl
tool of een andere tool die u misschien kent.
Wat is foutafhandeling?
Bij softwareontwikkeling zijn er twee verschillende soorten uitzonderingen: operationele en programmatische.
- Operationele storingen kunnen optreden tijdens runtime, en om te voorkomen dat de toepassing abrupt wordt beëindigd, moeten we deze uitzonderingen correct afhandelen door middel van efficiënte foutafhandelingsmethoden.
- Programmatische uitzonderingen worden handmatig gegenereerd door een programmeur wanneer zich een uitzonderlijke toestand voordoet.
U kunt operationele uitzonderingen beschouwen als "onverwachte, maar voorziene" uitzonderingen (zoals toegang tot een index buiten de grenzen), en programmatische uitzonderingen als "verwachte en voorziene" uitzonderingen (zoals een uitzondering voor het opmaken van getallen).
Afhandeling van uitzonderingen is de procedure die wordt gebruikt om fouten in een programma op te sporen en op te lossen. Bij foutafhandeling worden berichten verzonden met daarin het type fout dat is opgetreden en de stapel waarop de fout is opgetreden.
Opmerking: In de informatica kunnen uitzonderingen worden hersteld van, en zijn ze doorgaans het gevolg van operationele of programmatische problemen tijdens runtime. Fouten ontstaan meestal door externe factoren, zoals hardwarebeperkingen, problemen met connectiviteit, gebrek aan geheugen, enz. In JavaScript worden de termen vaak door elkaar gebruikt en aangepaste uitzonderingen zijn afgeleid van de Error
klasse. De Error
class zelf vertegenwoordigt zowel fouten als uitzonderingen.
In Express verwijst uitzonderingsafhandeling naar hoe Express zichzelf instelt om synchrone en asynchrone uitzonderingen op te vangen en te verwerken. Het goede aan exception handling in Express is dat je als ontwikkelaar niet je eigen exception handlers hoeft te schrijven; Express wordt geleverd met een standaard uitzonderingshandler. De uitzonderingshandler helpt bij het identificeren van fouten en het rapporteren ervan aan de gebruiker. Het biedt ook verschillende herstelstrategieën en implementeert deze om uitzonderingen te beperken.
Hoewel dit misschien een heleboel dingen lijken die onder de motorkap gaan, vertraagt de afhandeling van uitzonderingen in Express het algehele proces van een programma niet of onderbreekt het de uitvoering ervan.
Afhandeling van uitzonderingen in Express begrijpen
Met de standaard foutafhandeling die bij Express wordt geleverd, hebben we een reeks middleware-functies in handen die helpen om fouten in route-afhandelaars automatisch op te sporen. Binnenkort zullen we een project opzetten om de theorie in de praktijk te brengen over hoe u de juiste fouten in een Express-app kunt retourneren en hoe u geen gevoelige informatie kunt lekken.
Middleware-functie definiëren in Express
De middlewarefuncties voor foutafhandeling zijn zo gedefinieerd dat ze een Error
object als de eerste invoerparameter, gevolgd door de standaardparameters van elke andere middlewarefunctie: request
, response
en next
. De next()
functie slaat alle huidige middleware over naar de volgende foutafhandelaar voor de router.
Foutafhandeling instellen in Express
Voer de volgende opdracht uit in uw terminal om een Node- en Express-app te maken:
$ mkdir error-handling-express
Laten we in de nieuw gemaakte map een nieuw Node-project initialiseren:
$ cd error-handling-express && npm init -y
Dit creëert een package.json
bestand in onze map.
Om een Express-server in onze Node-app te maken, moeten we het express
pakket, dotenv
voor het automatisch laden van omgevingsvariabelen .env
bestand in process.env
object, en nodemon
voor het herstarten van de node-app als er een bestandswijziging wordt opgemerkt in de map.
$ npm install express dotenv nodemon
Maak vervolgens een app.js
bestand in de projectmap die zal dienen als het indexbestand voor de app.
Nu we alle benodigde afhankelijkheden voor onze Express-app hebben geïnstalleerd, moeten we het script instellen voor het lezen van de app in de package.json
het dossier. Om dat te bereiken, heeft de package.json
bestand, zodat de scripts
object is zoals hieronder getoond:
"scripts": {
"start": "nodemon app.js"
},
U kunt het gebruik ook overslaan nodemon
, en gebruiken node app.js
gebruiken.
Een Express-server opzetten
Om de server in te stellen, moeten we eerst de verschillende pakketten importeren app.js
. We zullen ook een .env
bestand in de projectdirectory – om alle omgevingsvariabelen voor de toepassing op te slaan:
const express = require('express')
require('dotenv').config
PORT=4000
We hebben het poortnummer voor de app gedefinieerd in .env
, die is geladen en gelezen door dotenv
, en is later toegankelijk.
De Express-server initialiseren
Nu moeten we de Express-server initialiseren en onze app laten luisteren naar het app-poortnummer, samen met een verzoek om een testroute - /test
. Laten we updaten app.js
, onder de importverklaringen:
const app = express();
const port = process.env.PORT || 4000;
app.get("/test", async (req, res) => {
return res.status(200).json({ success: true });
});
app.listen(port, () => {
console.log(`Server is running at port ${port}`);
});
Vanaf nu zullen we leren hoe we verschillende gebruiksgevallen van operationele fouten die kunnen optreden, in Express moeten behandelen.
Omgaan met niet gevonden fouten in Express
Stel dat u alle gebruikers moet ophalen uit een database met gebruikers, dan kunt u efficiënt omgaan met een mogelijk foutscenario waarbij er geen gegevens in de database staan, door de logica in een try/catch
block - in de hoop een fout op te vangen die zou kunnen projecteren in het catch
blok:
const getUser = () => undefined;
app.get("/get-user", async (req, res) => {
try {
const user = getUser();
if (!user) {
throw new Error('User not found');
}
} catch (error) {
console.log(error);
res.status(400).send(error.message)
}
return res.status(200).json({
success: true
});
});
Dit resulteert in:
User not found
Nu, wanneer dit verzoek is gedaan (u kunt testen met Postman) en er bestaat geen gebruiker in de database, ontvangt de client een foutmelding met de tekst "Gebruiker niet gevonden". U zult ook merken dat de fout ook in de console wordt geregistreerd.
Foutafhandeling optimaliseren met Error Handler-middleware
We kunnen de ontwikkeling optimaliseren door een middleware voor foutafhandeling te maken die aan het einde van alle gedefinieerde routes komt, zodat als er een fout in een van de routes wordt gegooid, Express automatisch naar de volgende middleware kijkt en verder gaat in de lijst totdat het de foutafhandelaar bereikt. De foutafhandelaar verwerkt de fout en stuurt ook een reactie terug naar de client.
Bekijk onze praktische, praktische gids voor het leren van Git, met best-practices, door de industrie geaccepteerde normen en bijgevoegd spiekbriefje. Stop met Googlen op Git-commando's en eigenlijk leren het!
Maak om te beginnen een map met de naam middleware
in de projectdirectory en maak in deze map een bestand met de naam errorHandler.js
die de foutafhandelaar definieert:
const errorHandler = (error, req, res, next) => {
console.log(error);
res.status(400).send(error.message);
}
module.exports = errorHandler;
In onze middleware-functie hebben we Express erop gewezen dat dit geen standaard middleware-functie is, maar een foutafhandeling, door de error
parameter vóór de 3 basisparameters.
Nu gebruiken we de fouthandler in onze demo app.js
en behandel de initiële fout bij het ophalen van gebruikers met de error handler middleware, zoals hieronder weergegeven:
const getUser = () => undefined;
app.get("/get-user", async (req, res, next) => {
try {
const user = getUser();
if (!user) {
throw new Error("User not found");
}
} catch (error) {
return next(error);
}
});
app.use(errorHandler);
We kunnen onze code nog verder optimaliseren door een abstractie rond het try/catch
logica. We kunnen dit bereiken door een nieuwe map aan te maken in de projectdirectory met de naam utils
, en maak daarin een bestand met de naam tryCatch.js
.
Om de try-catch
logica - we kunnen een functie definiëren die een andere functie accepteert (bekend als de controleur) als parameter en retourneert an async
functie die een try/catch
voor elke ontvangen controller.
Als er een fout optreedt in de controller, wordt deze opgevangen in de catch
block en de volgende functie heet:
const tryCatch = (controller) => async (req, res, next) => {
try {
await controller(req, res);
} catch (error) {
return next(error);
}
};
module.exports = tryCatch;
Met de try/catch
abstractie, kunnen we onze code herstructureren om deze beknopter te maken door de try-catch
clausule expliciet bij het ophalen van gebruikers in de app.js
:
const getUser = () => undefined;
app.get(
"/get-user",
tryCatch(async (req, res) => {
const user = getUser();
if (!user) {
throw new Error("User not found");
}
res.status(400).send(error.message);
})
);
We hebben met succes de try-catch-logica geabstraheerd en onze code werkt nog steeds zoals voorheen.
Omgaan met validatiefouten in Express
Voor deze demo maken we een nieuwe route in onze Express-app om in te loggen – om een gebruikers-ID te valideren bij het inloggen. Eerst installeren we de joi
pakket, om te helpen bij het maken van een schema, waarmee we vereisten kunnen afdwingen:
$ npm i joi
Maak vervolgens een schema dat een Joi.object
met een userId
wat een nummer moet zijn en vereist is - wat betekent dat het verzoek moet overeenkomen met een object met een gebruikers-ID erop.
We kunnen de validate()
methode in het schemaobject om elke invoer tegen het schema te valideren:
const schema = Joi.object({
userId: Joi.number().required(),
});
app.post(
"/login",
tryCatch(async (req, res) => {
const {error, value} = schema.validate({});
if (error) throw error;
})
);
Als een leeg object wordt doorgegeven aan de validate()
methode, zou de fout correct worden afgehandeld en zou het foutbericht naar de client worden verzonden:
Op de console krijgen we ook toegang tot een details
array die verschillende details over de fout bevat die indien nodig aan de gebruiker kunnen worden meegedeeld.
Om specifiek validatiefouten zodanig af te handelen dat het juiste foutdetail per validatiefout wordt doorgegeven, kan de middleware voor foutafhandeling worden geherstructureerd:
const errorHandler = (error, req, res, next) => {
console.log(error);
if (error.name === "ValidationError") {
return res.status(400).send({
type: "ValidationError",
details: error.details,
});
}
res.status(400).send(error.message);
};
module.exports = errorHandler;
met errorHandler.js
nu aangepast, wanneer we hetzelfde verzoek doen met een leeg object doorgegeven aan de validate()
methode:
We hebben nu toegang tot een aangepast object dat berichten op een meer leesbare/vriendelijkere manier retourneert. Op deze manier kunnen we verschillende soorten fouten verzenden en afhandelen op basis van het soort fout dat binnenkomt.
Conclusie
In deze handleiding hebben we elk aspect van de foutafhandeling van Express.js besproken, inclusief hoe synchrone en asynchrone code standaard wordt afgehandeld, hoe u uw eigen foutklassen kunt maken, hoe u aangepaste middleware-functies voor foutafhandeling kunt schrijven en next
als de laatste vangsthandler
Zoals bij elke taak die er is, zijn er ook best practices tijdens de ontwikkeling, waaronder effectieve foutafhandeling, en vandaag hebben we geleerd hoe we fouten in een Express-app op een robuuste manier kunnen afhandelen.
Correct omgaan met fouten betekent niet alleen het verkorten van de ontwikkeltijd door het gemakkelijk vinden van bugs en fouten, maar ook het ontwikkelen van een robuuste codebase voor grootschalige toepassingen. In deze handleiding hebben we gezien hoe je middleware instelt voor het afhandelen van operationele fouten. Enkele andere manieren om de foutafhandeling te verbeteren, zijn onder meer: geen stacktraceringen verzenden, processen correct stoppen om niet-afgevangen uitzonderingen af te handelen, passende foutmeldingen geven, foutenlogboeken verzenden en een klasse instellen die de foutafhandeling uitbreidt. Error
klasse.
Ik hoop dat de voorbeelden die ik in deze zelfstudie heb gebruikt, leuk voor je waren. Ik heb verschillende scenario's behandeld die u mogelijk kunt tegenkomen bij het schrijven van een Express-toepassing voor gebruik in de echte wereld over foutbeheer. Alsjeblieft, laat het me weten als ik iets heb gemist. Het zal ons ten goede komen en mij ook helpen meer te leren. Fijne dag en bedankt voor het lezen.
U kunt verwijzen naar alle broncode die wordt gebruikt in het artikel op GitHub.