O autor selecionou o Free and Open Source Fund para receber uma doação como parte do programa Write for DOnations.
Introdução
Flask é um framework web leve em Python que fornece ferramentas e recursos úteis para criar aplicações web na linguagem Python.
Quando você está desenvolvendo uma aplicação web, inevitavelmente se deparará com situações onde sua aplicação se comporta de maneira contrária ao que você esperava. Você pode errar a grafia de uma variável, usar mal um loop for
, ou construir uma instrução if
de forma que levante uma exceção Python, como chamar uma função antes de declará-la, ou simplesmente procurar por uma página que não existe. Você achará mais fácil e tranquilo desenvolver suas aplicações Flask se aprender a lidar com erros e exceções adequadamente.
Neste tutorial, você construirá uma pequena aplicação web que demonstra como lidar com erros comuns que se encontram ao desenvolver uma aplicação web. Você criará páginas de erro personalizadas, usará o depurador Flask para solucionar exceções e utilizará o registro (logging) para acompanhar eventos em sua aplicação.
Pré-requisitos
-
Um ambiente de programação local em Python 3. Você pode seguir o tutorial para sua distribuição na série Como Instalar e Configurar um Ambiente de Programação Local para Python 3. Neste tutorial, chamaremos nosso diretório do projeto de
flask_app
. -
Um entendimento dos conceitos básicos do Flask, como rotas, funções de visualização e templates. Se você não está familiarizado com o Flask, confira Como Criar Sua Primeira Aplicação Web Usando Flask e Python e Como Usar Templates em uma Aplicação Flask.
-
Uma compreensão dos conceitos básicos de HTML. Você pode revisar nossa série de tutoriais Como Construir um Site com HTML para conhecimento de base.
Passo 1 — Usando o Depurador do Flask
Neste passo, você criará uma aplicação com alguns erros e a executará sem o modo de depuração para ver como a aplicação responde. Então, você a executará com o modo de depuração ativado e usará o depurador para solucionar erros na aplicação.
Com o seu ambiente de programação ativado e Flask instalado, abra um arquivo chamado app.py
para edição dentro do seu diretório flask_app
:
Adicione o seguinte código dentro do arquivo app.py
:
No código acima, primeiro importa a classe Flask
do pacote flask
. Em seguida, cria uma instância de aplicação Flask chamada app
. Utiliza o decorador @app.route()
para criar uma função de visualização chamada index()
, que chama a função render_template()
como valor de retorno, que por sua vez renderiza um template chamado index.html
. Existem dois erros neste código: o primeiro é que você não importou a função render_template()
, e o segundo é que o arquivo de template index.html
não existe.
Salve e feche o arquivo.
Em seguida, informe ao Flask sobre a aplicação usando a variável de ambiente FLASK_APP
com o seguinte comando (no Windows, use set
em vez de export
):
Depois, execute o servidor de aplicação usando o comando flask run
:
Você verá as seguintes informações em seu 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)
Esta saída fornece as seguintes informações:
-
A aplicação Flask que está sendo servida (
app.py
neste caso) -
O ambiente, que é
production
aqui. A mensagem de aviso enfatiza que este servidor não é para uma implantação em produção. Você está usando este servidor para desenvolvimento, então pode ignorar este aviso, mas para mais informações, consulte a página Opções de Implantação na documentação do Flask. Você também pode conferir este tutorial de implantação do Flask com Gunicorn, ou este com uWSGI, ou pode usar a Plataforma de Aplicativos da DigitalOcean para implantar seu aplicativo Flask seguindo o tutorial Como Implantar um Aplicativo Flask Usando Gunicorn na Plataforma de Aplicativos. -
O modo de depuração está desativado, o que significa que o depurador do Flask não está em execução e você não receberá mensagens de erro úteis em sua aplicação. Em um ambiente de produção, exibir erros detalhados expõe sua aplicação a vulnerabilidades de segurança.
-
O servidor está em execução no URL
http://127.0.0.1:5000/
. Para parar o servidor, useCTRL+C
, mas não faça isso agora mesmo.
Agora, visite a página inicial usando seu navegador:
http://127.0.0.1:5000/
Você verá uma mensagem que se parece com a seguinte:
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.
Este é o Erro Interno do Servidor 500, que é uma resposta de erro do servidor que indica que o servidor encontrou um erro interno no código da aplicação.
No terminal, você verá a seguinte saída:
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 -
O rastreamento acima passa pelo código que desencadeou o erro interno do servidor. A linha NameError: name 'render_template' is not defined
indica a causa raiz do problema: a função render_template()
não foi importada.
Como você pode ver aqui, você precisa ir ao terminal para solucionar erros, o que não é conveniente.
Você pode ter uma experiência de solução de problemas melhor ativando o modo de depuração no seu servidor de desenvolvimento. Para fazer isso, pare o servidor com CTRL+C
e defina a variável de ambiente FLASK_ENV
como development
, para que você possa executar a aplicação no modo de desenvolvimento (que ativa o depurador), usando o seguinte comando (no Windows, use set
em vez de export
):
Execute o servidor de desenvolvimento:
Você verá uma saída semelhante à seguinte no 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
Aqui, você vê que o ambiente agora é development
, o modo de depuração está ativado e o depurador está ativo. O Debugger PIN
é um PIN que você precisa para desbloquear o console no seu navegador (um shell interativo de Python que você pode acessar clicando no pequeno ícone de terminal encerrado na imagem abaixo).
Atualize a página inicial no seu navegador e você verá a seguinte página:
Aqui, você vê a mensagem de erro exibida de uma maneira mais fácil de entender. O primeiro título fornece o nome da exceção Python que causou o problema (NameError
neste caso). A segunda linha fornece o motivo direto (render_template()
não está definido, o que significa que não foi importado neste caso). Depois disso, você tem o rastreamento passando pelo código interno do Flask que foi executado. Leia o rastreamento de baixo para cima, porque a última linha no rastreamento geralmente tem as informações mais úteis.
Nota:
O ícone de terminal circulado permite que você execute código Python no navegador em diferentes frames. Isso é útil quando você deseja verificar o valor de uma variável da mesma forma que faria em um shell interativo de Python. Quando você clica no ícone do terminal, precisará digitar o código PIN do depurador que obteve ao executar o servidor. Você não precisará deste shell interativo neste tutorial.
Para resolver este problema de NameError
, mantenha o servidor em execução, abra uma nova janela de terminal, ative seu ambiente e abra o arquivo app.py
:
Modifique o arquivo para ficar da seguinte forma:
Salve e feche o arquivo.
Aqui, você importou a função render_template()
que estava faltando.
Com o servidor de desenvolvimento em execução, atualize a página inicial no seu navegador.
Desta vez, você verá uma página de erro com informações que se parecem com isto:
Outputjinja2.exceptions.TemplateNotFound
jinja2.exceptions.TemplateNotFound: index.html
Esta mensagem de erro indica que o template index.html
não existe.
Para corrigir isso, você criará um arquivo de template base.html
do qual outros templates herdarão para evitar repetição de código, e então um template index.html
que estende o template base.
Crie o diretório templates
, que é o diretório onde o Flask procura por arquivos de template. Em seguida, abra um arquivo base.html
usando seu editor favorito:
Adicione o seguinte código ao seu arquivo base.html
:
Salve e feche o arquivo.
Este template base contém todo o boilerplate HTML que você precisará reutilizar em seus outros templates. O bloco title
será substituído para definir um título para cada página, e o bloco content
será substituído pelo conteúdo de cada página. A barra de navegação possui dois links, um para a página inicial onde você usa a função auxiliar url_for()
para vincular à função de visualização index()
, e outro para uma página Sobre, caso você opte por incluir uma em sua aplicação.
Em seguida, abra um arquivo de modelo chamado index.html
, que herdará do modelo base.
Adicione o seguinte código a ele:
Salve e feche o arquivo.
No código acima, você estende o modelo base e substitui o bloco content
. Em seguida, define um título da página e o exibe em um cabeçalho H1
usando o bloco title
, e exibe uma saudação em um cabeçalho H2
.
Com o servidor de desenvolvimento em execução, atualize a página inicial no seu navegador.
Você verá que o aplicativo não exibe mais erros e a página inicial é exibida conforme esperado.
Agora, você usou o modo de depuração e viu como lidar com mensagens de erro. Em seguida, você abortará uma solicitação para responder com uma mensagem de erro de sua escolha e verá como responder com páginas de erro personalizadas.
Etapa 2 — Criando Páginas de Erro Personalizadas
Nesta etapa, você aprenderá como abortar solicitações e responder com uma mensagem de erro HTTP 404 para quando o usuário solicitar dados que não existem no servidor. Você também aprenderá como criar páginas de erro personalizadas para erros HTTP comuns, como o erro 404 Not Found
e o erro 500 Internal Server Error
.
Para demonstrar como abortar solicitações e responder com uma página de erro HTTP 404 personalizada, você criará uma página que exibe algumas mensagens. Se a mensagem solicitada não existir, você responderá com um erro 404.
Primeiro, abra seu arquivo app.py
para adicionar uma nova rota para a página de mensagens:
Adicione a seguinte rota no final do arquivo:
Salve e feche o arquivo.
Na rota acima, você tem uma variável de URL idx
. Este é o índice que determinará qual mensagem será exibida. Por exemplo, se a URL for /messages/0
, a primeira mensagem (Message Zero
) será exibida. Você usa o int
converter para aceitar apenas inteiros positivos, pois as variáveis de URL têm valores de string por padrão.
Dentro da função de visualização message()
, você tem uma lista Python regular chamada messages
com três mensagens. (Em um cenário do mundo real, essas mensagens viriam de um banco de dados, uma API ou outra fonte de dados externa.) A função retorna uma chamada para a função render_template()
com dois argumentos, message.html
como o arquivo de modelo, e uma variável message
que será passada para o modelo. Esta variável terá um item da lista messages
dependendo do valor da variável idx
na URL.
Em seguida, abra um novo arquivo de modelo message.html
:
Adicione o seguinte código a ele:
Salve e feche o arquivo.
No código acima, você estende o modelo base e sobrescreve o bloco content
. Adiciona um título (Messages
) em um cabeçalho H1 e exibe o valor da variável message
em um cabeçalho H2.
Com o servidor de desenvolvimento em execução, visite as seguintes URLs no seu navegador:
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
Você verá que o H2
contém o texto Message Zero
, Message One
ou Message Two
respectivamente em cada uma das três primeiras URLs. No entanto, na quarta URL, o servidor responderá com uma mensagem de erro IndexError: list index out of range
. Em um ambiente de produção, a resposta teria sido um 500 Internal Server Error
, mas a resposta adequada aqui é um 404 Not Found
para indicar que o servidor não pode encontrar uma mensagem com um índice de 3
.
Você pode responder com um erro 404
usando a função auxiliar abort()
do Flask. Para fazer isso, abra o arquivo app.py
:
Edite a primeira linha para importar a função abort()
. Em seguida, edite a função de visualização message()
adicionando uma cláusula try ... except
conforme mostrado nas partes destacadas abaixo:
Salve e feche o arquivo.
No código acima, você importa a função abort()
, que você usa para abortar a solicitação e responder com um erro. Na função de visualização message()
, você usa uma cláusula try ... except
para envolver a função. Primeiro, tenta retornar o template messages
com a mensagem que corresponde ao índice na URL. Se o índice não tiver uma mensagem correspondente, a exceção IndexError
será levantada. Então, você usa a cláusula except
para capturar esse erro e usa abort(404)
para abortar a solicitação e responder com um erro HTTP 404 Not Found
.
Com o servidor de desenvolvimento em execução, use seu navegador para revisitar a URL que respondeu com um IndexError
anteriormente (ou visite qualquer URL com um índice maior que 2):
http://127.0.0.1:5000/messages/3
Você verá a seguinte resposta:
Not Found
The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
Agora você tem uma mensagem de erro melhor que indica que o servidor não pôde encontrar a mensagem solicitada.
Em seguida, você fará um template para a página de erro 404 e outro para a página de erro 500.
Primeiro, você registrará uma função com o decorador especial @app.errorhandler()
como um manipulador para o erro 404
. Abra o arquivo app.py
para edição:
nano app.py
Edite o arquivo adicionando a parte destacada da seguinte forma:
Salve e feche o arquivo.
Aqui, você usa o decorador @app.errorhandler()
para registrar a função page_not_found()
como um manipulador de erro personalizado. A função recebe o erro como argumento e retorna uma chamada para a função render_template()
com um template chamado 404.html
. Você criará este template mais tarde e pode usar outro nome se desejar. Você também retorna o inteiro 404
após a chamada render_template()
. Isso informa ao Flask que o código de status na resposta deve ser 404
. Se você não adicioná-lo, o código de status de resposta padrão será 200
, o que significa que a solicitação foi bem-sucedida.
Em seguida, abra um novo template 404.html
:
Adicione o seguinte código a ele:
Salve e feche o arquivo.
Assim como qualquer outro template, você estende o template base, substitui o conteúdo dos blocos content
e title
, e adiciona seu próprio código HTML. Aqui, você tem um título com a tag <h1>
, uma tag <p>
com uma mensagem de erro personalizada informando ao usuário que a página não foi encontrada, e uma mensagem útil para usuários que podem ter inserido a URL manualmente.
Você pode usar qualquer HTML, CSS e JavaScript que desejar em suas páginas de erro da mesma maneira que faria em outros templates.
Com o servidor de desenvolvimento em execução, use seu navegador para revisitar a seguinte URL:
http://127.0.0.1:5000/messages/3
Você verá que a página agora possui a barra de navegação que está no template base e a mensagem de erro personalizada.
Da mesma forma, você pode adicionar uma página de erro personalizada para seus erros 500 Internal Server Error
. Abra o arquivo app.py
:
Adicione o seguinte manipulador de erro abaixo do manipulador de erro 404
:
Aqui, você usa o mesmo padrão que utilizou para o manipulador de erro 404
. Você usa o decorador app.errorhandler()
com um argumento 500
para transformar a função chamada internal_error()
em um manipulador de erro. Você renderiza um template chamado 500.html
e responde com um código de status 500
.
Em seguida, para demonstrar como o erro personalizado será apresentado, adicione uma rota que responda com um erro HTTP 500
no final do arquivo. Esta rota sempre fornecerá um 500 Internal Server Error
independentemente de o debugger estar em execução ou não:
Aqui, você cria uma rota /500
e usa a função abort()
para responder com um erro HTTP 500
.
Salve e feche o arquivo.
Em seguida, abra o novo template 500.html
:
Adicione o seguinte código a ele:
Salve e feche o arquivo.
Aqui, você faz a mesma coisa que fez com o template 404.html
. Você estende o template base e substitui o bloco de conteúdo com um título e duas mensagens personalizadas informando ao usuário sobre o erro interno do servidor.
Com o servidor de desenvolvimento em execução, visite a rota que responde com um erro 500
:
http://127.0.0.1:5000/500
Sua página personalizada aparecerá em vez da página de erro genérica.
Agora você sabe como usar páginas de erro personalizadas para erros HTTP em sua aplicação Flask. Em seguida, você aprenderá a usar o registro (logging) para rastrear eventos em sua aplicação. Rastrear eventos ajuda a entender como seu código se comporta, o que, por sua vez, auxilia no desenvolvimento e na resolução de problemas.
Passo 3 — Usando Logging para Rastrear Eventos em Sua Aplicação
Neste passo, você utilizará o registro (logging) para rastrear eventos que ocorrem quando o servidor está em execução e a aplicação está sendo usada, o que ajuda a ver o que está acontecendo no código da sua aplicação, facilitando a resolução de erros.
Você já viu registros sempre que o servidor de desenvolvimento está em execução, que geralmente se parecem com isto:
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 -
Nesses registros, você pode ver as seguintes informações:
127.0.0.1
: O host em que o servidor estava em execução.[21/Set/2021 14:36:45]
: A data e hora da solicitação.GET
: O método de solicitação HTTP. Neste caso,GET
é usado para recuperar dados./messages/2
: O caminho solicitado pelo usuário.HTTP/1.1
: A versão HTTP.200
ou404
: O código de status da resposta.
Esses logs ajudam a diagnosticar problemas que ocorrem em sua aplicação. Você pode registrar mais informações quando deseja saber mais detalhes sobre certas requisições usando o logger app.logger
que o Flask fornece.
Com o logging, você pode usar diferentes funções para reportar informações em diferentes níveis de logging. Cada nível indica um evento que ocorreu com um certo grau de severidade. As seguintes funções podem ser utilizadas:
app.logger.debug()
: Para informações detalhadas sobre o evento.app.logger.info()
: Confirmação de que as coisas estão funcionando como esperado.app.logger.warning()
: Indicação de que algo inesperado aconteceu (como “espaço em disco baixo”), mas a aplicação está funcionando como esperado.app.logger.error()
: Um erro ocorreu em alguma parte da aplicação.app.logger.critical()
: Um erro crítico; a aplicação inteira pode parar de funcionar.
Para demonstrar como usar o logger do Flask, abra seu arquivo app.py
para edição e registre alguns eventos:
Edite a função de visualização message()
para parecer como segue:
Salve e feche o arquivo.
Aqui, você registrou alguns eventos em diferentes níveis. Você usa app.logger.info()
para registrar um evento que está funcionando como esperado (que é um nível INFO
). Você usa app.logger.debug()
para informações detalhadas (DEBUG
nível), mencionando que a aplicação está agora recebendo uma mensagem com um índice específico. Então você usa app.logger.error()
para registrar o fato de que uma exceção IndexError
foi levantada com o índice específico que causou o problema (ERROR
nível, porque ocorreu um erro).
Visite o seguinte URL:
http://127.0.0.1:5000/messages/1
Você verá as seguintes informações no terminal onde seu servidor está rodando:
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 -
Aqui você vê a mensagem INFO
app.logger.info()
registra, e a mensagem DEBUG
com o número de índice que você registrou usando app.logger.debug()
.
Agora visite um URL para uma mensagem que não existe:
http://127.0.0.1:5000/messages/3
Você verá as seguintes informações no 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 -
Como você pode ver, você tem logs INFO
e DEBUG
que você viu antes, e um novo log ERROR
porque uma mensagem com índice 3
não existe.
Registrar eventos, informações detalhadas e erros ajuda a identificar onde algo deu errado e facilita a solução de problemas.
Você aprendeu neste passo como usar o logger do Flask. Confira Como Usar Logging em Python 3 para uma melhor compreensão de logging. Para uma análise aprofundada do logging, consulte a documentação de logging do Flask e a documentação do Python para logging.
Conclusão
Agora você sabe como usar o modo de depuração no Flask e como solucionar e corrigir alguns erros comuns que pode encontrar ao desenvolver uma aplicação web Flask. Você também criou páginas de erro personalizadas para erros HTTP comuns e utilizou o logger do Flask para rastrear eventos em sua aplicação, ajudando-o a inspecionar e entender como sua aplicação se comporta.
Se você deseja ler mais sobre Flask, confira a página de tópicos sobre Flask.
Source:
https://www.digitalocean.com/community/tutorials/how-to-handle-errors-in-a-flask-application