Обработка ошибок во Flask

Flask предоставляет гибкий механизм обработки ошибок, который позволяет перехватывать и обрабатывать различные ошибки в приложении.

Хорошая обработка ошибок — это не только «отсутствие ошибок» — это обеспечение дружелюбного опыта для пользователей, когда ошибки всё же возникают.

В этой главе рассказывается, как настраивать страницы ошибок и управлять журналами в Flask.


Настраиваемая страница ошибок

По умолчанию Flask отображает простую страницу с чёрным фоном и белым текстом для таких ошибок, как 404.

Использование@app.errorhandlerДекораторы можно использовать для настройки страниц ошибок для конкретных кодов состояния HTTP:

Пример

from flask import Flask, render_template

app = Flask(__name__)

# Обработка ошибки 404 — страница не найдена
@app.errorhandler(404)
def page_not_found(error):
    # Примечание: необходимо явно вернуть код состояния 404
    return render_template("404.html"), 404

# Обработка ошибки 500 — внутренняя ошибка сервера
@app.errorhandler(500)
def internal_error(error):
    return render_template("500.html"), 500

# Обработка ошибки 403 — доступ запрещён
@app.errorhandler(403)
def forbidden(error):
    return render_template("403.html"), 403

Соответствующий шаблон 404:

Пример

<!-- Путь к файлу: templates/404.html -->
<!DOCTYPE html>
<html>
<head>
    <title>404 - Страница не найдена</title>
    <style>
        body { text-align: center; padding-top: 60px; font-family: Arial; }
        h1 { font-size: 72px; color: #e74c3c; margin: 0; }
        p { color: #666; font-size: 18px; }
        a { color: #3498db; }
    </style>
</head>
<body>
    <h1>404</h1>
    <p>Извините, страница, которую вы посетили, не существует.</p>
    <p><a href="/">Вернуться на главную</a></p>
</body>
</html>

ВerrorhandlerВ декорированной функции,returnВы должны явно указать код состояния. Если не указать его, 404, Flask по умолчанию вернёт код состояния 200, и браузеры и поисковые системы не будут считать её страницей ошибки.


Регистрация классов исключений

Помимо кода состояния,@app.errorhandlerВы также можете напрямую регистрировать классы исключений:

Пример

from werkzeug.exceptions import HTTPException

@app.errorhandler(HTTPException)
def handle_http_exception(error):
    """Обрабатывать все HTTP-исключения единообразно (например, 400, 401, 403, 404 и т. д.)."""
    return f"""
<h1>Ошибка HTTP {error.code}</h1>
    <p>{error.description}</p>
<p><a href="/">Вернуться на главную страницу EXAMPLE</a></p>
    """
, error.code

Использование abort для вызова ошибок

В вашей функции представления используйтеabort(), чтобы активно вызвать HTTP-ошибку:

Пример

from flask import abort

# Имитация базы данных статей
articles = {
    1: {"title": Учебник Flask},
    2: {"title": "Основы Python"},
}

@app.get("/article/<int:article_id>")
def view_article(article_id):
    article = articles.get(article_id)

    if article is None:
        # Статья не существует, вернуть 404
        # Параметр description будет передан в errorhandler
        abort(404, description=f"Статья с ID {article_id} не существует")

    return f"<h1>{article['title']}</h1>"

@app.get("/admin")
def admin_panel():
    # Пользователь без прав администратора получает доступ к административному бэкенду
    abort(403, description="У вас нет прав администратора")

Логирование

Flask используетloggingмодуль из стандартной библиотеки Python, черезapp.loggerЗатем вы можете логировать запись.

Логирование крайне важно для поиска неисправностей — не используйте простоprint(), так как логи дают более богатый контекст и лучший контроль.

Пример

from flask import Flask, request

app = Flask(__name__)

@app.route("/")
def index():
    # Различные уровни логирования
    app.logger.debug("Доступ к главной странице")                    # Отладочная информация, обычно не выводится в рабочей среде
    app.logger.info("Пользователь с IP: %s", request.remote_addr)  # Общая информация
    app.logger.warning("Обнаружен необычный шаблон доступа")         # Предупреждение: требует внимания, но не влияет на работу
    app.logger.error("Не удалось подключиться к базе данных")               # Ошибка: функциональность затронута
    app.logger.critical("Недостаточно места на диске, служба скоро остановится")  # Критическая ошибка: служба может остановиться
    return "OK"

Уровни логирования (от низкого к высокому):

Уровень Сценарий использования
DEBUG Подробная информация во время отладки при разработке по умолчанию не выводится в производственной среде.
INFO Общая информация о времени выполнения, например логи запросов и запуск сервиса
WARNING Предупреждающие сообщения, потенциальные проблемы, не влияющие на текущую работу
ERROR Сообщения об ошибках, функция не сработала, но сервис продолжает работать
CRITICAL Критические ошибки, могут привести к остановке сервиса

В режиме Debug уровень логирования Flask автоматически устанавливается наDEBUG. В производственных средах устанавливайте его при необходимости наINFOилиWARNING, чтобы не выводить слишком много бесполезной информации.


Настройка вывода логов

Записывайте логи в файл для упрощения последующего анализа и устранения неполадок:

Пример

import logging
from logging.handlers import RotatingFileHandler

# Настройка файлового обработчика логов: ротация после достижения файлом лога 10MB
handler = RotatingFileHandler(
    "example_app.log",     # Путь к файлу лога
    maxBytes=10 * 1024 * 1024,  # Максимальный размер одного файла 10MB
    backupCount=5          # Хранить последние 5 резервных копий
)

# Установить формат лога
handler.setFormatter(logging.Formatter(
    "[%(asctime)s] %(levelname)s in %(module)s: %(message)s"
))

# Добавить обработчик в логгер Flask
app.logger.addHandler(handler)
app.logger.setLevel(logging.INFO)

Перехват необработанных исключений

Использованиеapp.errorhandler(500)Вы можете перехватывать необработанные исключения и записывать их в логи:

Пример

import traceback

@app.errorhandler(500)
def internal_error(error):
    # Записать полную трассировку стека исключения
    app.logger.error("Внутренняя ошибка сервера:\n%s", traceback.format_exc())

    # Показать пользователю понятную страницу ошибки
    return """
<h1>500 - Внутренняя ошибка сервера</h1>
<p>Извините, на сервере произошла непредвиденная ошибка. Мы записали информацию о проблеме. Пожалуйста, повторите попытку позже.</p>
<p>Если проблема сохраняется, обратитесь в службу технической поддержки EXAMPLE.</p>
    """
, 500

Краткий справочник по распространённым кодам ошибок HTTP

Код состояния Значение Частые причины
400 Некорректный запрос Некорректные параметры запроса, отсутствуют обязательные поля
401 Не авторизован Пользователь не вошёл в систему или не прошёл аутентификацию
403 Запрещено Пользователь вошёл в систему, но не имеет разрешения на доступ
404 Не найдено Ресурс (статья, пользователь и т. д.) не существует
405 Метод не разрешён Использование неправильного HTTP-метода (например, использование GET для доступа к конечной точке POST)
500 Внутренняя ошибка сервера Необработанные ошибки, такие как исключения в коде и сбои подключения к базе данных
Другие расширения