De auteur koos ervoor om een donatie te doen aan het Vrij en Open Source Fonds als onderdeel van het Write for DOnations programma.
Inleiding
Flask is een lichtgewicht Python webframework dat nuttige tools en functies biedt voor het maken van webapplicaties in de Python taal.
Wanneer je een webapplicatie ontwikkelt, zul je onvermijdelijk situaties tegenkomen waarbij je applicatie zich niet gedraagt zoals je verwacht. Je zou een variabele verkeerd kunnen schrijven, een for
-lus verkeerd kunnen gebruiken, of een if
-statement op een manier kunnen construeren die een Python-uitzondering veroorzaakt, zoals een functie aanroepen voordat je deze hebt gedeclareerd, of gewoon naar een pagina zoeken die niet bestaat. Je zult het gemakkelijker en soepeler vinden om je Flask-applicaties te ontwikkelen als je leert hoe je fouten en uitzonderingen goed kunt afhandelen.
In deze tutorial bouw je een kleine webapplicatie die laat zien hoe je veelvoorkomende fouten kunt afhandelen die je tegenkomt bij het ontwikkelen van een webapplicatie. Je maakt aangepaste foutpagina’s, gebruikt de Flask debugger om uitzonderingen op te sporen, en gebruikt logging om gebeurtenissen in je applicatie te volgen.
Vereisten
-
Een lokale Python 3 programmeeromgeving. U kunt de handleiding voor uw distributie volgen in de serie Hoe Installeer en Stel Een Lokale Programmeeromgeving In voor Python 3. In deze tutorial noemen we onze projectmap
flask_app
. -
Een begrip van basisconcepten van Flask, zoals routes, view functies en templates. Als u niet bekend bent met Flask, bekijk dan Hoe Maak Je Je Eerste Webapplicatie Met Flask en Python en Hoe Gebruik Je Templates in Een Flask Applicatie.
-
Een begrip van basis HTML concepten. Je kunt onze Hoe bouw je een website met HTML tutorial serie bekijken voor achtergrondkennis.
Stap 1 — Het Gebruik van De Flask Debugger
In deze stap maak je een applicatie die een paar fouten heeft en voer je deze uit zonder debug mode om te zien hoe de applicatie reageert. Daarna voer je het uit met debug mode aan en gebruik je de debugger om applicatiefouten op te lossen.
Met je programmeeromgeving geactiveerd en Flask geïnstalleerd, open een bestand genaamd app.py
voor bewerken in je flask_app
directory:
Voeg de volgende code toe in het app.py
bestand:
In de bovenstaande code, importeer je eerst de Flask
klasse uit het flask
pakket. Vervolgens maak je een Flask applicatie-instantie genaamd app
. Je gebruikt de @app.route()
decorator om een weergavefunctie genaamd index()
te maken, die de render_template()
functie aanroept als retourwaarde, die op zijn beurt een template genaamd index.html
rendert. Er zijn twee fouten in deze code: de eerste is dat je de render_template()
functie niet hebt geïmporteerd, en de tweede is dat het index.html
templatebestand niet bestaat.
Sla het bestand op en sluit het.
Volgende, informeer Flask over de applicatie met behulp van de FLASK_APP
omgevingsvariabele met de volgende opdracht (op Windows, gebruik set
in plaats van export
):
Start vervolgens de applicatieserver met de flask run
command:
Je zult de volgende informatie in je terminal zien:
Output * Serving Flask app 'app' (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Deze uitvoer geeft de volgende informatie:
-
De Flask applicatie die wordt geserveerd (
app.py
in dit geval) -
De omgeving, die hier
production
is. De waarschuwingsbericht benadrukt dat deze server niet bedoeld is voor een productie-implementatie. Je gebruikt deze server voor ontwikkeling, dus je kunt deze waarschuwing negeren, maar voor meer informatie, zie de pagina Implementatieopties in de Flask documentatie. Je kunt ook deze Flask implementatie zelfstudie met Gunicorn bekijken, of deze met uWSGI, of je kunt DigitalOcean App Platform gebruiken om je Flask applicatie te implementeren door de Hoe een Flask App te Implementeren met Gunicorn naar App Platform zelfstudie te volgen. -
De debugmodus is uitgeschakeld, wat betekent dat de Flask debugger niet draait en je geen behulpzame foutmeldingen in je applicatie ontvangt. In een productieomgeving brengt het tonen van gedetailleerde fouten je applicatie in kwetsbaarheden voor beveiligingsrisico’s.
-
De server draait op de URL
http://127.0.0.1:5000/
. Om de server te stoppen, gebruikCTRL+C
, maar doe dat nog niet.
Bezoek nu de indexpagina met je browser:
http://127.0.0.1:5000/
Je zult een bericht zien dat er als volgt uitziet:
OutputInternal Server Error
The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.
Dit is de 500 Internal Server Error, een serverfoutmelding die aangeeft dat de server een interne fout heeft ondervonden in de applicatiecode.
In de terminal zie je de volgende output:
Output[2021-09-12 15:16:56,441] ERROR in app: Exception on / [GET]
Traceback (most recent call last):
File "/home/abd/.local/lib/python3.9/site-packages/flask/app.py", line 2070, in wsgi_app
response = self.full_dispatch_request()
File "/home/abd/.local/lib/python3.9/site-packages/flask/app.py", line 1515, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/abd/.local/lib/python3.9/site-packages/flask/app.py", line 1513, in full_dispatch_request
rv = self.dispatch_request()
File "/home/abd/.local/lib/python3.9/site-packages/flask/app.py", line 1499, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
File "/home/abd/python/flask/series03/flask_app/app.py", line 8, in index
return render_template('index.html')
NameError: name 'render_template' is not defined
127.0.0.1 - - [12/Sep/2021 15:16:56] "GET / HTTP/1.1" 500 -
De traceback hierboven doorloopt de code die de interne serverfout heeft veroorzaakt. De regel NameError: name 'render_template' is not defined
geeft de oorzaak van het probleem aan: de render_template()
functie is niet geïmporteerd.
Zoals je hier kunt zien, moet je naar de terminal gaan om fouten op te lossen, wat niet handig is.
Je kunt een betere foutopsporingservaring krijgen door de debugmodus in je ontwikkelingsserver in te schakelen. Om dit te doen, stop de server met CTRL+C
en stel de omgevingsvariabele FLASK_ENV
in op development
, zodat je de applicatie in ontwikkelingsmodus kunt uitvoeren (waarmee de debugger wordt ingeschakeld), met de volgende opdracht (gebruik op Windows set
in plaats van export
):
Start de ontwikkelingsserver:
Je zult een uitvoer zien die vergelijkbaar is met het volgende in de terminal:
Output * Serving Flask app 'app' (lazy loading)
* Environment: development
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 120-484-907
Hier zie je dat de omgeving nu development
is, de debugmodus aan staat en de debugger actief is. De Debugger PIN
is een PIN-code die je nodig hebt om de console in je browser te ontgrendelen (een interactieve Python-shell die je kunt openen door op het kleine terminalpictogram te klikken, omcirkeld in de onderstaande afbeelding).
Vernieuw de indexpagina in je browser en je zult de volgende pagina zien:
Hier zie je het foutbericht weergegeven op een manier die gemakkelijker te begrijpen is. De eerste kop geeft je de naam van de Python-uitzondering die het probleem veroorzaakte (NameError
in dit geval). De tweede regel geeft je de directe oorzaak (render_template()
is niet gedefinieerd, wat betekent dat het in dit geval niet is geïmporteerd). Daarna heb je de traceback die door de innerlijke Flask-code gaat die is uitgevoerd. Lees de traceback vanaf de onderkant omhoog, omdat de laatste regel in de traceback meestal de meest bruikbare informatie bevat.
Opmerking:
Het omcirkelde terminalpictogram stelt je in staat Python-code in de browser uit te voeren op verschillende frames. Dit is handig wanneer je de waarde van een variabele wilt controleren zoals je dat zou doen in een interactieve Python-shell. Wanneer je op het terminalpictogram klikt, moet je de Debugger PIN-code invoeren die je hebt ontvangen toen je de server startte. Je hebt deze interactieve shell niet nodig in deze tutorial.
Om dit NameError
probleem op te lossen, laat de server draaien, open een nieuw terminalvenster, activeer je omgeving en open je app.py
bestand:
Wijzig het bestand zodat het er als volgt uitziet:
Bewaar en sluit het bestand.
Hier heb je de render_template()
functie geïmporteerd die miste.
Met de ontwikkelingsserver draaiend, vernieuw de indexpagina in je browser.
Deze keer zie je een foutpagina met informatie die er zo uitziet:
Outputjinja2.exceptions.TemplateNotFound
jinja2.exceptions.TemplateNotFound: index.html
Dit foutbericht geeft aan dat de index.html
template niet bestaat.
Om dit op te lossen, maak je een base.html
templatebestand waar andere templates van zullen erven om codeherhaling te voorkomen, gevolgd door een index.html
template die de basis-template uitbreidt.
Maak de templates
directory aan, wat de directory is waar Flask naar templatebestanden zoekt. Open vervolgens een base.html
bestand met je favoriete editor:
Voeg de volgende code toe aan je base.html
bestand:
Bewaar en sluit het bestand.
Deze basistemplate bevat alle HTML boilerplate die je nodig hebt om te hergebruiken in je andere templates. Het title
blok zal worden vervangen om een titel voor elke pagina in te stellen, en het content
blok zal worden vervangen door de inhoud van elke pagina. De navigatiebalk heeft twee links, één voor de indexpagina waar je de url_for()
helperfunctie gebruikt om te linken naar de index()
view functie, en de andere voor een About pagina als je die in je applicatie wilt opnemen.
Vervolgens opent u een sjabloonbestand genaamd index.html
, dat overerft van de basis-sjabloon.
Voeg de volgende code toe aan het bestand:
Sla het bestand op en sluit het.
In de bovenstaande code breidt u de basis-sjabloon uit en overschrijft u het content
blok. Vervolgens stelt u een paginatitel in en geeft u deze weer in een H1
koptekst met behulp van het title
blok, en geeft u een groet weer in een H2
koptekst.
Met de ontwikkelingsserver actief, vernieuw de indexpagina in uw browser.
U zult zien dat de applicatie geen fouten meer weergeeft en de indexpagina wordt weergegeven zoals verwacht.
U hebt nu debugmodus gebruikt en gezien hoe u foutmeldingen kunt afhandelen. Vervolgens zult u een verzoek afbreken om te reageren met een foutmelding naar keuze en zult u zien hoe u reageert met aangepaste foutpagina’s.
Stap 2 — Aangepaste Foutpagina’s Maken
In deze stap leert u hoe u verzoeken kunt afbreken en reageert met een 404 HTTP-foutmelding voor wanneer de gebruiker gegevens opvraagt die niet op de server bestaan. U zult ook leren hoe u aangepaste foutpagina’s maakt voor veelvoorkomende HTTP-fouten, zoals de 404 Niet Gevonden
fout en de 500 Interne Serverfout
fout.
Om te demonstreren hoe je verzoeken kunt afbreken en reageert met een aangepaste 404 HTTP-foutpagina, ga je een pagina maken die een paar berichten weergeeft. Als het gevraagde bericht niet bestaat, reageer je met een 404-fout.
Open eerst je app.py
bestand om een nieuwe route toe te voegen voor de berichtenpagina:
Voeg de volgende route toe aan het einde van het bestand:
Bewaar en sluit het bestand.
In de bovenstaande route heb je een URL-variabele idx
. Dit is de index die bepaalt welk bericht wordt weergegeven. Bijvoorbeeld, als de URL /messages/0
is, wordt het eerste bericht (Message Zero
) weergegeven. Je gebruikt de int
converter om alleen positieve gehele getallen te accepteren, omdat URL-variabelen standaard stringwaarden hebben.
Binnen de message()
weergavefunctie heb je een reguliere Python-lijst genaamd messages
met drie berichten. (In een echte situatie zouden deze berichten uit een database, een API of een andere externe gegevensbron komen.) De functie retourneert een aanroep naar de render_template()
functie met twee argumenten, message.html
als de templatebestand, en een message
variabele die aan de template wordt doorgegeven. Deze variabele krijgt een lijstitem uit de messages
lijst afhankelijk van de waarde van de idx
variabele in de URL.
Open vervolgens een nieuw message.html
templatebestand:
Voeg de volgende code toe:
Opslaan en het bestand sluiten.
In de bovenstaande code breid je de basis template uit en overschrijf je het content
blok. Je voegt een titel (Messages
) toe in een H1-kop en toont de waarde van de message
variabele in een H2-kop.
Met de ontwikkelserver actief, bezoek de volgende URL’s in je browser:
http://127.0.0.1:5000/messages/0
http://127.0.0.1:5000/messages/1
http://127.0.0.1:5000/messages/2
http://127.0.0.1:5000/messages/3
Je zult zien dat de H2
respectievelijk de tekst Message Zero
, Message One
, of Message Two
bevat op elk van de eerste drie URL’s. Op de vierde URL zal de server echter reageren met een IndexError: list index out of range
foutmelding. In een productieomgeving zou het antwoord een 500 Internal Server Error
zijn geweest, maar het juiste antwoord hier is een 404 Not Found
om aan te geven dat de server geen bericht met een index van 3
kan vinden.
Je kunt reageren met een 404
fout met behulp van Flask’s abort()
helperfunctie. Om dit te doen, open het app.py
bestand:
Bewerk de eerste regel om de abort()
functie te importeren. Bewerk vervolgens de message()
view functie door een try ... except
clausule toe te voegen zoals weergegeven in de gemarkeerde onderdelen hieronder:
Opslaan en het bestand sluiten.
In de code hierboven, importeer je de abort()
functie, die je gebruikt om de aanvraag af te breken en met een fout te reageren. In de message()
view functie, gebruik je een try ... except
clausule om de functie te omwikkelen. Je probeert eerst de messages
template te retourneren met het bericht dat overeenkomt met de index in de URL. Als de index geen corresponderend bericht heeft, zal de IndexError
uitzondering worden opgeworpen. Vervolgens gebruik je de except
clausule om die fout te vangen, en je gebruikt abort(404)
om de aanvraag af te breken en te reageren met een 404 Not Found
HTTP-fout.
Met de ontwikkelserver draaiend, gebruik je je browser om de URL die eerder met een IndexError
reageerde opnieuw te bezoeken (of bezoek elke URL met een index groter dan 2):
http://127.0.0.1:5000/messages/3
Je zult de volgende reactie zien:
Not Found
The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
Je hebt nu een beter foutbericht dat aangeeft dat de server het gevraagde bericht niet kon vinden.
Volgende, zul je een template maken voor de 404-foutpagina en een voor de 500-foutpagina.
Eerst zul je een functie registreren met de speciale @app.errorhandler()
decorator als handler voor de 404
fout. Open het app.py
bestand voor bewerking:
nano app.py
Bewerk het bestand door het gemarkeerde deel als volgt toe te voegen:
Sla het bestand op en sluit het.
Hier gebruik je de @app.errorhandler()
decorator om de functie page_not_found()
te registreren als een aangepaste foutafhandelaar. De functie neemt de fout als argument en retourneert een aanroep naar de render_template()
functie met een sjabloon genaamd 404.html
. Je zult dit sjabloon later aanmaken en je kunt een andere naam gebruiken als je wilt. Je retourneert ook het gehele getal 404
na de render_template()
aanroep. Dit vertelt Flask dat de statuscode in het antwoord 404
moet zijn. Als je dit niet toevoegt, zal de standaard statuscode respons 200
zijn, wat betekent dat de aanvraag is geslaagd.
Open vervolgens een nieuw 404.html
sjabloon:
Voeg de volgende code toe:
Sla het bestand op en sluit het.
Net als elk ander sjabloon, breid je het basis sjabloon uit, vervang je de inhoud van de content
en title
blokken, en voeg je je eigen HTML-code toe. Hier heb je een <h1>
kop als titel, een <p>
tag met een aangepast foutbericht dat de gebruiker informeert dat de pagina niet is gevonden, en een behulpzaam bericht voor gebruikers die de URL misschien handmatig hebben ingevoerd.
Je kunt elke gewenste HTML, CSS en JavaScript gebruiken in je foutpagina’s op dezelfde manier als in andere sjablonen.
Met de ontwikkelingsserver draaiend, gebruik je je browser om de volgende URL opnieuw te bezoeken:
http://127.0.0.1:5000/messages/3
Je zult zien dat de pagina nu de navigatiebalk heeft die in het basis sjabloon zit en het aangepaste foutbericht.
Evenzo kun je een aangepaste foutpagina toevoegen voor je 500 Internal Server Error
fouten. Open het app.py
bestand:
Voeg de volgende fouthandler toe onder de 404
fouthandler:
Hier gebruik je hetzelfde patroon als voor de 404
fouthandler. Je gebruikt de app.errorhandler()
decorator met een 500
argument om een functie genaamd internal_error()
te maken in een fouthandler. Je rendert een template genaamd 500.html
en reageert met een statuscode van 500
.
Vervolgens om te demonstreren hoe de aangepaste fout wordt gepresenteerd, voeg je een route toe die reageert met een 500
HTTP-fout aan het einde van het bestand. Deze route geeft altijd een 500 Internal Server Error
ongeacht of de debugger actief is of niet:
Hier maak je een route /500
en gebruik je de abort()
functie om te reageren met een 500
HTTP-fout.
Sla het bestand op en sluit het.
Open vervolgens de nieuwe 500.html
template:
Voeg de volgende code toe:
Sla het bestand op en sluit het.
Hier doe je hetzelfde als met de 404.html
template. Je breidt de basis-template uit en vervangt het inhoudsblok met een titel en twee aangepaste berichten die de gebruiker informeren over de interne serverfout.
Met de ontwikkelserver actief, bezoek de route die reageert met een 500
fout:
http://127.0.0.1:5000/500
Je aangepaste pagina verschijnt in plaats van de generieke foutpagina.
Je weet nu hoe je aangepaste foutpagina’s kunt gebruiken voor HTTP-fouten in je Flask-applicatie. Vervolgens leer je hoe je logging kunt gebruiken om gebeurtenissen in je applicatie te volgen. Het volgen van gebeurtenissen helpt je te begrijpen hoe je code zich gedraagt, wat weer helpt bij ontwikkeling en probleemoplossing.
Stap 3 — Logging gebruiken om Gebeurtenissen in Je Applicatie te Volgen
In deze stap gebruik je logging om gebeurtenissen te volgen die plaatsvinden wanneer de server draait en de applicatie wordt gebruikt, wat helpt om te zien wat er gebeurt in je applicatiecode zodat je fouten gemakkelijker kunt oplossen.
Je hebt al logs gezien telkens wanneer de ontwikkelserver draait, die er meestal zo uitzien:
127.0.0.1 - - [21/Sep/2021 14:36:45] "GET /messages/1 HTTP/1.1" 200 -
127.0.0.1 - - [21/Sep/2021 14:36:52] "GET /messages/2 HTTP/1.1" 200 -
127.0.0.1 - - [21/Sep/2021 14:36:54] "GET /messages/3 HTTP/1.1" 404 -
In deze logs kun je de volgende informatie zien:
127.0.0.1
: De host waarop de server draaide.[21/Sep/2021 14:36:45]
: De datum en tijd van de aanvraag.GET
: De HTTP-verzoekmethode. In dit geval wordtGET
gebruikt om gegevens op te halen./messages/2
: Het pad dat de gebruiker heeft opgevraagd.HTTP/1.1
: De HTTP-versie.200
of404
: De statuscode van het antwoord.
Deze logs helpen je om problemen te diagnosticeren die zich in je applicatie voordoen. Je kunt meer informatie loggen wanneer je meer details wilt weten over bepaalde verzoeken met behulp van de logger app.logger
die Flask biedt.
Met logging kun je verschillende functies gebruiken om informatie te rapporteren op verschillende logniveaus. Elk niveau geeft aan dat een gebeurtenis heeft plaatsgevonden met een bepaalde mate van ernst. De volgende functies kunnen worden gebruikt:
app.logger.debug()
: Voor gedetailleerde informatie over de gebeurtenis.app.logger.info()
: Bevestiging dat alles werkt zoals verwacht.app.logger.warning()
: Aanduiding dat er iets onverwachts is gebeurd (zoals “weinig schijfruimte”), maar de applicatie werkt zoals verwacht.app.logger.error()
: Er is een fout opgetreden in een deel van de applicatie.app.logger.critical()
: Een kritieke fout; de hele applicatie zou kunnen stoppen met werken.
Om te demonstreren hoe je de Flask logger kunt gebruiken, open je app.py
bestand voor bewerking om een aantal gebeurtenissen te loggen:
Bewerk de message()
view functie om er als volgt uit te zien:
Sla het bestand op en sluit het.
Hier heb je een aantal gebeurtenissen op verschillende niveaus geregistreerd. Je gebruikt app.logger.info()
om een gebeurtenis te loggen die naar verwachting werkt (een INFO
niveau). Je gebruikt app.logger.debug()
voor gedetailleerde informatie (DEBUG
niveau), waarbij je vermeldt dat de applicatie nu een bericht ontvangt met een specifiek indexnummer. Vervolgens gebruik je app.logger.error()
om te loggen dat er een IndexError
uitzondering is opgetreden met het specifieke indexnummer dat het probleem veroorzaakte (ERROR
niveau, omdat er een fout is opgetreden).
Bezoek de volgende URL:
http://127.0.0.1:5000/messages/1
Je zult de volgende informatie zien in de terminal waar je server draait:
Output
[2021-09-21 15:17:02,625] INFO in app: Building the messages list...
[2021-09-21 15:17:02,626] DEBUG in app: Get message with index: 1
127.0.0.1 - - [21/Sep/2021 15:17:02] "GET /messages/1 HTTP/1.1" 200 -
Hier zie je het INFO
bericht dat app.logger.info()
logt, en het DEBUG
bericht met het indexnummer dat je hebt gelogd met app.logger.debug()
.
Bezoek nu een URL voor een bericht dat niet bestaat:
http://127.0.0.1:5000/messages/3
Je zult de volgende informatie zien in de terminal:
Output[2021-09-21 15:33:43,899] INFO in app: Building the messages list...
[2021-09-21 15:33:43,899] DEBUG in app: Get message with index: 3
[2021-09-21 15:33:43,900] ERROR in app: Index 3 is causing an IndexError
127.0.0.1 - - [21/Sep/2021 15:33:43] "GET /messages/3 HTTP/1.1" 404 -
Zoals je kunt zien, heb je INFO
en DEBUG
logs die je eerder hebt gezien, en een nieuwe ERROR
log omdat een bericht met een index van 3
niet bestaat.
Het loggen van gebeurtenissen, gedetailleerde informatie en fouten helpt je te identificeren waar iets fout is gegaan en maakt het oplossen van problemen eenvoudiger.
Je hebt in deze stap geleerd hoe je de Flask logger kunt gebruiken. Bekijk How To Use Logging in Python 3 voor een beter begrip van logging. Voor een diepgaand overzicht van logging, zie de Flask logging documentatie en de Python documentatie voor logging.
Conclusie
Je weet nu hoe je debug mode in Flask kunt gebruiken, en hoe je enkele veelvoorkomende fouten kunt oplossen die je kunt tegenkomen bij het ontwikkelen van een Flask webapplicatie. Je hebt ook aangepaste foutpagina’s gemaakt voor veelvoorkomende HTTP-fouten, en je hebt de Flask logger gebruikt om gebeurtenissen in je applicatie te volgen om je te helpen inspecteren en erachter te komen hoe je applicatie zich gedraagt.
Als je meer wilt lezen over Flask, bekijk dan de Flask topic page.
Source:
https://www.digitalocean.com/community/tutorials/how-to-handle-errors-in-a-flask-application