L’auteur a choisi le Fonds libre et open source pour recevoir une donation dans le cadre du programme Write for DOnations.
Introduction
Flask est un framework web léger en Python qui fournit des outils et des fonctionnalités utiles pour créer des applications web en langage Python.
Lorsque vous développez une application web, vous rencontrerez inévitablement des situations où votre application se comporte d’une manière contraire à ce que vous attendiez. Vous pourriez mal orthographier une variable, mal utiliser une boucle for
, ou construire une instruction if
de manière à provoquer une exception Python, comme appeler une fonction avant de la déclarer, ou simplement chercher une page qui n’existe pas. Vous trouverez plus facile et plus fluide de développer vos applications Flask si vous apprenez à gérer correctement les erreurs et les exceptions.
Dans ce tutoriel, vous allez construire une petite application web qui montre comment gérer les erreurs courantes auxquelles on est confronté lors du développement d’une application web. Vous créerez des pages d’erreur personnalisées, utiliserez le débogueur Flask pour résoudre les exceptions, et utiliserez la journalisation pour suivre les événements dans votre application.
Prérequis
-
Un environnement de programmation Python 3 local. Vous pouvez suivre le tutoriel pour votre distribution dans la série Comment installer et configurer un environnement de programmation local pour Python 3. Dans ce tutoriel, nous appellerons notre répertoire de projet
flask_app
. -
Une compréhension des concepts de base de Flask, tels que les routes, les fonctions de vue et les templates. Si vous n’êtes pas familier avec Flask, consultez Comment créer votre première application Web avec Flask et Python et Comment utiliser les templates dans une application Flask.
-
Une compréhension des concepts de base de HTML. Vous pouvez consulter notre série de tutoriels Comment créer un site web avec HTML pour des connaissances de base.
Étape 1 — Utilisation du débogueur Flask
Dans cette étape, vous allez créer une application présentant quelques erreurs et l’exécuter sans mode débogage pour voir comment l’application réagit. Ensuite, vous l’exécuterez avec le mode débogage activé et utiliserez le débogueur pour résoudre les erreurs de l’application.
Avec votre environnement de programmation activé et Flask installé, ouvrez un fichier appelé app.py
pour l’édition à l’intérieur de votre répertoire flask_app
:
Ajoutez le code suivant à l’intérieur du fichier app.py
:
Dans le code ci-dessus, vous importez d’abord la classe Flask
depuis le package flask
. Ensuite, vous créez une instance d’application Flask appelée app
. Vous utilisez le décorateur @app.route()
pour créer une fonction d’affichage appelée index()
, qui appelle la fonction render_template()
comme valeur de retour, qui à son tour rend un modèle appelé index.html
. Il y a deux erreurs dans ce code : la première est que vous n’avez pas importé la fonction render_template()
, et la deuxième est que le fichier modèle index.html
n’existe pas.
Enregistrez et fermez le fichier.
Ensuite, informe Flask sur l’application en utilisant la variable d’environnement FLASK_APP
avec la commande suivante (sur Windows, utilisez set
au lieu de export
):
Puis exécutez le serveur d’application en utilisant la commande flask run
:
Vous verrez les informations suivantes dans votre terminal:
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)
Cette sortie fournit les informations suivantes:
-
L’application Flask servie (
app.py
dans ce cas) -
L’environnement, qui est ici
production
. Le message d’avertissement souligne que ce serveur n’est pas destiné à un déploiement en production. Vous utilisez ce serveur pour le développement, vous pouvez donc ignorer cet avertissement, mais pour plus d’informations, consultez la page Options de déploiement dans la documentation de Flask. Vous pouvez également consulter ce tutoriel de déploiement Flask avec Gunicorn, ou celui avec uWSGI, ou vous pouvez utiliser la plateforme App de DigitalOcean pour déployer votre application Flask en suivant le tutoriel Comment déployer une application Flask avec Gunicorn sur App Platform. -
Le mode débogage est désactivé, ce qui signifie que le débogueur Flask n’est pas en cours d’exécution et que vous ne recevrez pas de messages d’erreur utiles dans votre application. Dans un environnement de production, l’affichage d’erreurs détaillées expose votre application à des vulnérabilités de sécurité.
-
Le serveur fonctionne sur l’URL
http://127.0.0.1:5000/
. Pour arrêter le serveur, utilisezCTRL+C
, mais ne le faites pas encore.
Maintenant, visitez la page d’index en utilisant votre navigateur:
http://127.0.0.1:5000/
Vous verrez un message qui ressemble à ce qui suit:
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.
Ceci est l’Erreur interne du serveur 500, qui est une réponse d’erreur du serveur indiquant que le serveur a rencontré une erreur interne dans le code de l’application.
Dans le terminal, vous verrez la sortie suivante:
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 -
La traceback ci-dessus passe en revue le code qui a déclenché l’erreur interne du serveur. La ligne NameError: le nom 'render_template' n'est pas défini
donne la cause racine du problème : la fonction render_template()
n’a pas été importée.
Comme vous pouvez le voir ici, vous devez aller dans le terminal pour résoudre les erreurs, ce qui n’est pas pratique.
Vous pouvez avoir une meilleure expérience de dépannage en activant le mode débogage sur votre serveur de développement. Pour ce faire, arrêtez le serveur avec CTRL+C
et définissez la variable d’environnement FLASK_ENV
sur development
, afin de pouvoir exécuter l’application en mode développement (ce qui active le débogueur), en utilisant la commande suivante (sous Windows, utilisez set
au lieu de export
):
Exécutez le serveur de développement:
Vous verrez une sortie similaire à la suivante dans le 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
Ici, vous voyez que l’environnement est maintenant development
, le mode débogage est activé et le débogueur est actif. Le Debugger PIN
est un code PIN dont vous avez besoin pour déverrouiller la console dans votre navigateur (un shell Python interactif auquel vous pouvez accéder en cliquant sur l’icône de terminal entourée dans l’image ci-dessous).
Actualisez la page d’index dans votre navigateur et vous verrez la page suivante :
Ici, vous voyez le message d’erreur affiché de manière plus facile à comprendre. Le premier titre vous donne le nom de l’exception Python qui a causé le problème (NameError
dans ce cas). La deuxième ligne vous donne la raison directe (render_template()
n’est pas défini, ce qui signifie qu’il n’est pas importé dans ce cas). Ensuite, vous avez la trace qui parcourt le code interne de Flask qui a été exécuté. Lisez la trace de bas en haut, car la dernière ligne de la trace contient généralement les informations les plus utiles.
Remarque :
L’icône de terminal entourée vous permet d’exécuter du code Python dans le navigateur sur différents cadres. Cela est utile lorsque vous souhaitez vérifier la valeur d’une variable comme vous le feriez dans un shell Python interactif. Lorsque vous cliquez sur l’icône de terminal, vous devrez entrer le code PIN du débogueur que vous avez obtenu lorsque vous avez démarré le serveur. Vous n’aurez pas besoin de ce shell interactif dans ce tutoriel.
Pour résoudre ce problème de NameError
, laissez le serveur en cours d’exécution, ouvrez une nouvelle fenêtre de terminal, activez votre environnement, et ouvrez votre fichier app.py
:
Modifiez le fichier pour qu’il ressemble à ceci:
Enregistrez et fermez le fichier.
Ici, vous avez importé la fonction render_template()
qui manquait.
Avec le serveur de développement en cours d’exécution, actualisez la page d’index dans votre navigateur.
Cette fois, vous verrez une page d’erreur avec des informations qui ressemblent à ceci:
Outputjinja2.exceptions.TemplateNotFound
jinja2.exceptions.TemplateNotFound: index.html
Ce message d’erreur indique que le modèle index.html
n’existe pas.
Pour résoudre cela, vous allez créer un fichier modèle base.html
dont les autres modèles hériteront pour éviter la répétition de code, puis un modèle index.html
qui étendra le modèle de base.
Créez le répertoire templates
, qui est le répertoire où Flask cherche les fichiers modèles. Ensuite, ouvrez un fichier base.html
avec votre éditeur favori:
Ajoutez le code suivant à votre fichier base.html
:
Enregistrez et fermez le fichier.
Ce modèle de base contient tout le code HTML dont vous aurez besoin pour réutiliser dans vos autres modèles. Le bloc title
sera remplacé pour définir un titre pour chaque page, et le bloc content
sera remplacé par le contenu de chaque page. La barre de navigation comporte deux liens, un pour la page d’index où vous utilisez la fonction d’aide url_for()
pour lier à la fonction de vue index()
, et l’autre pour une page À propos si vous choisissez d’en inclure une dans votre application.
Ensuite, ouvrez un fichier modèle appelé index.html
, qui héritera du modèle de base.
Ajoutez le code suivant à celui-ci :
Enregistrez et fermez le fichier.
Dans le code ci-dessus, vous étendez le modèle de base et remplacez le bloc content
. Vous définissez ensuite un titre de page et l’affichez dans un en-tête H1
en utilisant le bloc title
, et affichez un message de bienvenue dans un en-tête H2
.
Avec le serveur de développement en cours d’exécution, actualisez la page d’index dans votre navigateur.
Vous verrez que l’application n’affiche plus d’erreurs et que la page d’index s’affiche comme prévu.
Vous avez maintenant utilisé le mode débogage et vu comment gérer les messages d’erreur. Ensuite, vous allez abandonner une requête pour répondre avec un message d’erreur de votre choix, et voir comment répondre avec des pages d’erreur personnalisées.
Étape 2 — Création de pages d’erreur personnalisées
Dans cette étape, vous apprendrez à abandonner les requêtes et à répondre avec un message d’erreur HTTP 404 pour les cas où l’utilisateur demande des données qui n’existent pas sur le serveur. Vous apprendrez également à créer des pages d’erreur personnalisées pour les erreurs HTTP courantes, telles que l’erreur 404 Not Found
et l’erreur 500 Internal Server Error
.
Pour montrer comment annuler les requêtes et répondre avec une page d’erreur HTTP 404 personnalisée, vous allez créer une page qui affiche quelques messages. Si le message demandé n’existe pas, vous répondrez avec une erreur 404.
Tout d’abord, ouvrez votre fichier app.py
pour ajouter une nouvelle route pour la page des messages:
Ajoutez la route suivante à la fin du fichier:
Enregistrez et fermez le fichier.
Dans la route ci-dessus, vous avez une variable d’URL idx
. C’est l’index qui déterminera quel message sera affiché. Par exemple, si l’URL est /messages/0
, le premier message (Message Zero
) sera affiché. Vous utilisez le int
converter pour accepter uniquement des entiers positifs, car les variables d’URL ont des valeurs de chaîne par défaut.
À l’intérieur de la fonction de vue message()
, vous avez une liste Python régulière appelée messages
avec trois messages. (Dans un scénario réel, ces messages proviendraient d’une base de données, d’une API ou d’une autre source de données externe.) La fonction retourne un appel à la fonction render_template()
avec deux arguments, message.html
en tant que fichier de modèle, et une variable message
qui sera passée au modèle. Cette variable aura un élément de la liste messages
en fonction de la valeur de la variable idx
dans l’URL.
Ensuite, ouvrez un nouveau fichier de modèle message.html
:
Ajoutez le code suivant à celui-ci:
Enregistrez et fermez le fichier.
Dans le code ci-dessus, vous étendez le modèle de base et remplacez le bloc content
. Vous ajoutez un titre (Messages
) dans un titre H1, et affichez la valeur de la variable message
dans un titre H2.
Avec le serveur de développement en cours d’exécution, visitez les URL suivantes dans votre navigateur :
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
Vous verrez que le H2
contient le texte Message Zero
, Message One
, ou Message Two
respectivement sur chacune des trois premières URL. Cependant, sur la quatrième URL, le serveur répondra avec un message d’erreur IndexError: list index out of range
. Dans un environnement de production, la réponse aurait été un 500 Internal Server Error
, mais la réponse appropriée ici est un 404 Not Found
pour indiquer que le serveur ne peut pas trouver un message avec un index de 3
.
Vous pouvez répondre avec une erreur 404
en utilisant la fonction d’aide abort()
de Flask. Pour ce faire, ouvrez le fichier app.py
:
Modifiez la première ligne pour importer la fonction abort()
. Ensuite, modifiez la fonction de vue message()
en ajoutant une clause try ... except
comme indiqué dans les parties en surbrillance ci-dessous :
Enregistrez et fermez le fichier.
Dans le code ci-dessus, vous importez la fonction abort()
, que vous utilisez pour abandonner la requête et répondre avec une erreur. Dans la fonction de vue message()
, vous utilisez une clause try ... except
pour encapsuler la fonction. Vous essayez d’abord de retourner le template messages
avec le message correspondant à l’index dans l’URL. Si l’index n’a pas de message correspondant, l’exception IndexError
sera levée. Vous utilisez ensuite la clause except
pour attraper cette erreur, et vous utilisez abort(404)
pour abandonner la requête et répondre avec une erreur HTTP 404 Not Found
.
Avec le serveur de développement en cours d’exécution, utilisez votre navigateur pour revisiter l’URL qui a répondu avec un IndexError
plus tôt (ou visitez n’importe quelle URL avec un index supérieur à 2):
http://127.0.0.1:5000/messages/3
Vous verrez la réponse suivante:
Not Found
The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
Vous avez maintenant un meilleur message d’erreur indiquant que le serveur n’a pas pu trouver le message demandé.
Ensuite, vous allez créer un template pour la page d’erreur 404 et un pour la page d’erreur 500.
Tout d’abord, vous allez enregistrer une fonction avec le décorateur spécial @app.errorhandler()
comme gestionnaire pour l’erreur 404
. Ouvrez le fichier app.py
pour l’éditer:
nano app.py
Modifiez le fichier en ajoutant la partie en surbrillance comme suit:
Enregistrez et fermez le fichier.
Ici, vous utilisez le décorateur @app.errorhandler()
pour enregistrer la fonction page_not_found()
en tant que gestionnaire d’erreur personnalisé. La fonction prend l’erreur en argument et retourne un appel à la fonction render_template()
avec un modèle appelé 404.html
. Vous créerez ce modèle plus tard et vous pouvez utiliser un autre nom si vous le souhaitez. Vous retournez également l’entier 404
après l’appel à render_template()
. Cela indique à Flask que le code de statut dans la réponse doit être 404
. Si vous ne l’ajoutez pas, le code de statut de réponse par défaut sera 200
, ce qui signifie que la requête a réussi.
Ensuite, ouvrez un nouveau modèle 404.html
:
Ajoutez le code suivant à celui-ci:
Enregistrez et fermez le fichier.
Comme tout autre modèle, vous étendez le modèle de base, vous remplacez le contenu des blocs content
et title
, et vous ajoutez votre propre code HTML. Ici, vous avez un titre sous forme de balise <h1>
, une balise <p>
avec un message d’erreur personnalisé indiquant que la page n’a pas été trouvée, et un message utile pour les utilisateurs qui auraient entré l’URL manuellement.
Vous pouvez utiliser n’importe quel HTML, CSS et JavaScript que vous souhaitez dans vos pages d’erreur de la même manière que vous le feriez dans d’autres modèles.
Avec le serveur de développement en cours d’exécution, utilisez votre navigateur pour revisiter l’URL suivante:
http://127.0.0.1:5000/messages/3
Vous verrez que la page a maintenant la barre de navigation présente dans le modèle de base et le message d’erreur personnalisé.
De même, vous pouvez ajouter une page d’erreur personnalisée pour vos erreurs 500 Internal Server Error
. Ouvrez le fichier app.py
:
Ajoutez le gestionnaire d’erreur suivant sous le gestionnaire d’erreur 404
:
Ici, vous utilisez le même modèle que pour le gestionnaire d’erreur 404
. Vous utilisez le décorateur app.errorhandler()
avec un argument 500
pour transformer une fonction appelée internal_error()
en gestionnaire d’erreur. Vous affichez un modèle appelé 500.html
et répondez avec un code d’état 500
.
Ensuite, pour montrer comment l’erreur personnalisée sera présentée, ajoutez une route qui répond avec une erreur HTTP 500
à la fin du fichier. Cette route donnera toujours une 500 Internal Server Error
indépendamment du fait que le débogueur soit en cours d’exécution ou non:
Ici, vous créez une route /500
et utilisez la fonction abort()
pour répondre avec une erreur HTTP 500
.
Enregistrez et fermez le fichier.
Ensuite, ouvrez le nouveau modèle 500.html
:
Ajoutez le code suivant à celui-ci:
Enregistrez et fermez le fichier.
Ici, vous faites la même chose que vous avez fait avec le modèle 404.html
. Vous étendez le modèle de base et remplacez le bloc de contenu par un titre et deux messages personnalisés informant l’utilisateur de l’erreur interne du serveur.
Avec le serveur de développement en cours d’exécution, visitez la route qui répond avec une erreur 500
:
http://127.0.0.1:5000/500
Votre page personnalisée apparaîtra à la place de la page d’erreur générique.
Vous savez maintenant comment utiliser des pages d’erreur personnalisées pour les erreurs HTTP dans votre application Flask. Ensuite, vous apprendrez à utiliser la journalisation pour suivre les événements dans votre application. Le suivi des événements vous aide à comprendre comment votre code se comporte, ce qui facilite le développement et la résolution des problèmes.
Étape 3 — Utilisation de la journalisation pour suivre les événements dans votre application
Dans cette étape, vous utiliserez la journalisation pour suivre les événements qui se produisent lorsque le serveur est en cours d’exécution et que l’application est utilisée, ce qui vous aide à voir ce qui se passe dans votre code d’application afin de résoudre les erreurs plus facilement.
Vous avez déjà vu des journaux chaque fois que le serveur de développement est en cours d’exécution, qui ressemblent généralement à ceci :
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 -
Dans ces journaux, vous pouvez voir les informations suivantes :
127.0.0.1
: L’hôte sur lequel le serveur était en cours d’exécution.[21/Sep/2021 14:36:45]
: La date et l’heure de la requête.GET
: La méthode de requête HTTP. Dans ce cas,GET
est utilisé pour récupérer des données./messages/2
: Le chemin demandé par l’utilisateur.HTTP/1.1
: La version HTTP.200
ou404
: Le code de statut de la réponse.
Ces journaux vous aident à diagnostiquer les problèmes qui se produisent dans votre application. Vous pouvez enregistrer plus d’informations lorsque vous souhaitez connaître plus de détails sur certaines requêtes en utilisant le logger app.logger
fourni par Flask.
Avec la journalisation, vous pouvez utiliser différentes fonctions pour signaler des informations à différents niveaux de journalisation. Chaque niveau indique qu’un événement s’est produit avec un certain degré de gravité. Les fonctions suivantes peuvent être utilisées:
app.logger.debug()
: Pour des informations détaillées sur l’événement.app.logger.info()
: Confirmation que les choses fonctionnent comme prévu.app.logger.warning()
: Indication qu’un événement inattendu s’est produit (comme « espace disque faible »), mais l’application fonctionne comme prévu.app.logger.error()
: Une erreur s’est produite dans une partie de l’application.app.logger.critical()
: Une erreur critique ; l’ensemble de l’application pourrait cesser de fonctionner.
Pour montrer comment utiliser le logger Flask, ouvrez votre fichier app.py
pour édition afin de journaliser quelques événements:
Modifiez la fonction de vue message()
pour qu’elle ressemble à ce qui suit:
Enregistrez et fermez le fichier.
Ici, vous avez enregistré quelques événements à différents niveaux. Vous utilisez app.logger.info()
pour enregistrer un événement qui fonctionne comme prévu (ce qui est un niveau INFO
). Vous utilisez app.logger.debug()
pour des informations détaillées (DEBUG
niveau), mentionnant que l’application reçoit maintenant un message avec un index spécifique. Ensuite, vous utilisez app.logger.error()
pour enregistrer le fait qu’une exception IndexError
a été levée avec l’index spécifique qui a causé le problème (ERROR
niveau, car une erreur s’est produite).
Visitez l’URL suivante :
http://127.0.0.1:5000/messages/1
Vous verrez les informations suivantes dans le terminal où votre serveur est en cours d’exécution :
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 -
Ici, vous voyez le message INFO
app.logger.info()
enregistre, et le message DEBUG
avec le numéro d’index que vous avez enregistré en utilisant app.logger.debug()
.
Maintenant, visitez une URL pour un message qui n’existe pas :
http://127.0.0.1:5000/messages/3
Vous verrez les informations suivantes dans le 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 -
Comme vous pouvez le voir, vous avez les journaux INFO
et DEBUG
que vous avez vus auparavant, et un nouveau journal ERROR
car un message avec un index de 3
n’existe pas.
Enregistrer des événements, des informations détaillées et des erreurs vous aide à identifier où quelque chose s’est mal passé et rend le dépannage plus facile.
Vous avez appris à cet étape comment utiliser le logger Flask. Consultez Comment utiliser la journalisation en Python 3 pour une meilleure compréhension de la journalisation. Pour une étude approfondie de la journalisation, consultez la documentation de journalisation de Flask et la documentation Python pour la journalisation.
Conclusion
Vous savez maintenant comment utiliser le mode débogage dans Flask, et comment résoudre et corriger certaines erreurs courantes que vous pourriez rencontrer lors du développement d’une application web Flask. Vous avez également créé des pages d’erreur personnalisées pour les erreurs HTTP courantes, et vous avez utilisé le logger Flask pour suivre les événements dans votre application afin de vous aider à inspecter et à comprendre comment votre application se comporte.
Si vous souhaitez en savoir plus sur Flask, consultez la page thématique Flask.
Source:
https://www.digitalocean.com/community/tutorials/how-to-handle-errors-in-a-flask-application