Обработка ошибок и страницы 404/500
Ошибки неизбежны: страница не найдена, нет прав, сервер упал. Профессиональное приложение встречает их понятными страницами, а не голым стектрейсом.
Когда что-то идёт не так, Flask возвращает страницу ошибки по коду: 404 (не найдено), 403 (запрещено), 500 (ошибка сервера). По умолчанию они невзрачные. Декоратор errorhandler позволяет показать свою страницу — с дизайном сайта и полезной подсказкой.
Ошибки бывают двух видов: ожидаемые (пользователь зашёл на несуществующий URL — 404) и неожиданные (баг в коде — 500). И те и другие нужно встречать достойно. abort(code) генерирует ошибку намеренно, а errorhandler ловит её и рисует страницу.
from flask import abort, render_template
@app.route("/post/<int:post_id>")
def show_post(post_id):
post = db.session.get(Post, post_id)
if post is None:
abort(404) # намеренно вызвать 404
return render_template("post.html", post=post)
@app.errorhandler(404)
def not_found(error):
return render_template("404.html"), 404
@app.errorhandler(500)
def server_error(error):
return render_template("500.html"), 500
Обработчик возвращает кортеж: шаблон и статус-код. Код важен — он должен остаться 404/500, чтобы поисковики и клиенты поняли ситуацию правильно.
Обработка ошибок отличает любительский проект от профессионального. Пользователь неизбежно попадёт на несуществующий URL, потеряет права доступа или наткнётся на баг — и встретить его должна аккуратная страница в стиле сайта с навигацией назад, а не голый стектрейс или белый экран. Различай два рода ошибок: ожидаемые клиентские (404, 403) обрабатываешь штатно через abort и errorhandler, а неожиданные серверные (500) обязательно логируешь, чтобы увидеть и починить причину, — пойманное и проглоченное без лога исключение становится невидимым багом. И помни про статус-код: кастомная страница 404 должна возвращать именно 404, иначе поисковик примет «ненайдено» за настоящую страницу и проиндексирует пустышку.
Как работает под капотом
Flask держит таблицу обработчиков по кодам. Когда внутри запроса возникает исключение или вызывается abort, Flask ищет подходящий errorhandler. Нашёл — рисует твою страницу; не нашёл — отдаёт дефолтную.
внутри view: abort(404) или исключение
│
▼
Flask ищет errorhandler по коду
├─ найден (404) → render 404.html, статус 404
└─ не найден → дефолтная страница Flask
для 500: в debug=True показывается трейсбек (только разработка!)
Смоделируем диспетчер ошибок обычным Python.
handlers = {}
def errorhandler(code):
def deco(func):
handlers[code] = func
return func
return deco
@errorhandler(404)
def not_found(): return "Страница не найдена :("
@errorhandler(500)
def server_error(): return "Что-то сломалось на сервере"
def dispatch(code):
handler = handlers.get(code)
if handler:
return (code, handler())
return (code, "Стандартная ошибка")
print(dispatch(404))
print(dispatch(500))
print(dispatch(403)) # обработчика нет → дефолт
Запусти: для зарегистрированных кодов вызывается своя страница, для остальных — дефолт. Так Flask подменяет невзрачные ошибки фирменными страницами.
Частые ошибки
- Вернуть страницу с кодом 200. Обработчик 404 должен вернуть именно 404, иначе поисковик проиндексирует «пустышку».
- Показывать трейсбек в продакшене. debug=True раскрывает внутренности и позволяет выполнять код. В проде — только дружелюбная 500.
- Глотать исключения без логирования. Поймал 500 — залогируй причину, иначе баг невидим.
Best practices
- Сделай кастомные 404 и 500 в стиле сайта с навигацией назад.
- Возвращай корректный статус-код вместе со страницей.
- Логируй 500-ошибки; в проде debug всегда выключен.
Что запомнить
- abort(code) вызывает ошибку намеренно; errorhandler ловит её.
- Кастомные страницы 404/500 возвращают корректный статус-код.
- 500-ошибки логируют, чтобы видеть и чинить причину.
- debug=True в продакшене — критическая уязвимость; всегда выключен.
Итог: abort вызывает ошибку, errorhandler ловит её и рисует свою страницу с верным кодом. Это превращает аварии в управляемый, понятный пользователю опыт. Дальше — тестирование приложения.