Обработка ошибок во Flask
Flask предоставляет гибкий механизм обработки ошибок, который позволяет перехватывать и обрабатывать различные ошибки в приложении.
Хорошая обработка ошибок — это не только «отсутствие ошибок» — это обеспечение дружелюбного опыта для пользователей, когда ошибки всё же возникают.
В этой главе рассказывается, как настраивать страницы ошибок и управлять журналами в Flask.
Настраиваемая страница ошибок
По умолчанию Flask отображает простую страницу с чёрным фоном и белым текстом для таких ошибок, как 404.
Использование@app.errorhandlerДекораторы можно использовать для настройки страниц ошибок для конкретных кодов состояния HTTP:
Пример
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:
Пример
<!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Вы также можете напрямую регистрировать классы исключений:
Пример
@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-ошибку:
Пример
# Имитация базы данных статей
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(), так как логи дают более богатый контекст и лучший контроль.
Пример
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, чтобы не выводить слишком много бесполезной информации.
Настройка вывода логов
Записывайте логи в файл для упрощения последующего анализа и устранения неполадок:
Пример
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)Вы можете перехватывать необработанные исключения и записывать их в логи:
Пример
@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 | Внутренняя ошибка сервера | Необработанные ошибки, такие как исключения в коде и сбои подключения к базе данных |