Spec-Zone.ru › Flask 1.1

Ошибки приложения

Журнал изменений

Новая версия 0.3.

Приложения выходят из строя, серверы выходят из строя. Рано или поздно вы столкнетесь с исключением в рабочей среде. Даже если ваш код на 100% правильный, время от времени вы все равно будете видеть исключения. Почему? Потому что все остальное может выйти из строя. Вот некоторые ситуации, когда совершенно нормальный код может привести к ошибкам сервера:

  • клиент прервал запрос на ранней стадии, а приложение все еще считывало данные из входящих данных
  • сервер базы данных был перегружен и не смог обработать запрос
  • полностью заполнен файловый сервер
  • жесткий диск вышел из строя
  • сервер бэкенда перегружен
  • программирование ошибка в библиотеке, которую вы используете
  • соединение сети сервера с другой системой вышло из строя

И это всего лишь небольшой пример проблем, с которыми вы можете столкнуться. Итак, как мы справляемся с подобными проблемами? По умолчанию, если ваше приложение работает в режиме производства, Flask отобразит для вас очень простую страницу и запишет исключение в logger.

Но вы можете сделать больше, и мы рассмотрим некоторые лучшие настройки для обработки ошибок.

Инструменты регистрации ошибок

Отправка писем об ошибках, даже если только для критических, может стать непосильной задачей, если достаточно пользователей сталкиваются с ошибкой, и журналы ошибок обычно не просматриваются. Вот почему мы рекомендуем использовать Sentry для обработки ошибок приложения. Он доступен как проект с открытым исходным кодом на GitHub и также доступен как хостинг-версия, которую вы можете бесплатно попробовать. Sentry агрегирует дублированные ошибки, записывает полный стек вызовов и локальные переменные для отладки и отправляет вам письма на основе новых ошибок или пороговых значений частоты.

Чтобы использовать Sentry, вам необходимо установить клиент sentry-sdk с дополнительными flask зависимостями:

$ pip install sentry-sdk[flask]

Затем добавьте это в ваше приложение Flask:

import sentry_sdk
from sentry_sdk.integrations.flask import FlaskIntegration

sentry_sdk.init('YOUR_DSN_HERE',integrations=[FlaskIntegration()])

Значение YOUR_DSN_HERE необходимо заменить значением DSN, которое вы получаете из вашей установки Sentry.

После установки ошибки, приводящие к ошибке «Внутренняя ошибка сервера», автоматически сообщаются в Sentry, и оттуда вы можете получать уведомления об ошибках.

Дополнительные материалы для чтения:

  • Sentry также поддерживает перехват ошибок из вашей очереди задач (RQ, Celery) аналогичным образом. Более подробную информацию см. в документации Python SDK.
  • Начало работы с Sentry
  • Документация, специфичная для Flask.

Обработчики ошибок

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

Обработчик ошибок — это обычная функция представления, которая возвращает ответ, но вместо того, чтобы быть зарегистрированной для маршрута, она регистрируется для исключения или кода состояния HTTP, который может быть поднят при попытке обработать запрос.

Регистрация

Регистрируйте обработчики, используя декоратор errorhandler(). Или используйте register_error_handler(), чтобы зарегистрировать функцию позже. Помните, что при возврате ответа необходимо установить код ошибки.

@app.errorhandler(werkzeug.exceptions.BadRequest)
def handle_bad_request(e):
    return 'bad request!', 400

# or, without the decorator
app.register_error_handler(400, handle_bad_request)

werkzeug.exceptions.HTTPException подклассы, такие как BadRequest, и их коды HTTP взаимозаменяемы при регистрации обработчиков. (BadRequest.code == 400)

Нестандартные коды HTTP не могут быть зарегистрированы кодом, потому что они неизвестны Werkzeug. Вместо этого определите подкласс HTTPException с соответствующим кодом и зарегистрируйте, и поднимите этот класс исключения.

class InsufficientStorage(werkzeug.exceptions.HTTPException):
    code = 507
    description = 'Not enough storage space.'

app.register_error_handler(InsufficientStorage, handle_507)

raise InsufficientStorage()

Обработчики могут быть зарегистрированы для любого класса исключений, а не только для HTTPException подклассов или кодов состояния HTTP. Обработчики могут быть зарегистрированы для конкретного класса или для всех подклассов родительского класса.

Обработка

Когда Flask перехватывает исключение во время обработки запроса, он сначала ищет его по коду. Если для кода не зарегистрирован обработчик, он ищет его по иерархии классов; выбирается наиболее конкретный обработчик. Если обработчик не зарегистрирован, HTTPException подклассы показывают сообщение общего характера о их коде, а другие исключения преобразуются в общую ошибку «Внутренняя ошибка сервера 500».

Например, если возникает экземпляр ConnectionRefusedError, и зарегистрирован обработчик для ConnectionError и ConnectionRefusedError, вызывается более конкретный обработчик ConnectionRefusedError с экземпляром исключения для создания ответа.

Обработчики, зарегистрированные в модуле, имеют приоритет перед обработчиками, зарегистрированными глобально в приложении, если модуль обрабатывает запрос, который вызывает исключение. Однако модуль не может обработать ошибки маршрутизации 404, потому что ошибка 404 возникает на уровне маршрутизации до определения модуля.

Общие обработчики исключений

Можно зарегистрировать обработчики ошибок для очень общих базовых классов, таких как HTTPException или даже Exception. Однако имейте в виду, что они будут перехватывать больше, чем вы могли ожидать.

Обработчик ошибок для HTTPException может быть полезен для преобразования стандартных страниц HTML ошибок в JSON, например. Однако этот обработчик будет срабатывать в случаях, не связанных с вашими действиями, таких как ошибки 404 и 405 при маршрутизации. Тщательно настройте свой обработчик, чтобы не потерять информацию об ошибке HTTP.

from flask import json
from werkzeug.exceptions import HTTPException

@app.errorhandler(HTTPException)
def handle_exception(e):
    """Return JSON instead of HTML for HTTP errors."""
    # start with the correct headers and status code from the error
    response = e.get_response()
    # replace the body with JSON
    response.data = json.dumps({
        "code": e.code,
        "name": e.name,
        "description": e.description,
    })
    response.content_type = "application/json"
    return response

Обработчик ошибок для Exception может показаться полезным для изменения того, как все ошибки, даже необработанные, представляются пользователю. Однако это аналогично выполнению except Exception: в Python, он перехватит все иначе необработанные ошибки, включая все коды состояния HTTP. В большинстве случаев будет безопаснее регистрировать обработчики для более конкретных исключений. Так как экземпляры HTTPException являются допустимыми WSGI ответами, вы также можете передавать их напрямую.

from werkzeug.exceptions import HTTPException

@app.errorhandler(Exception)
def handle_exception(e):
    # pass through HTTP errors
    if isinstance(e, HTTPException):
        return e

    # now you're handling non-HTTP exceptions only
    return render_template("500_generic.html", e=e), 500

Обработчики ошибок по-прежнему учитывают иерархию классов исключений. Если вы зарегистрируете обработчики как для HTTPException так и для Exception, обработчик Exception не будет обрабатывать подклассы HTTPException, потому что обработчик HTTPException более специфичен.

Необработанные исключения

Когда обработчик ошибок не зарегистрирован для исключения, вместо этого возвращается ошибка 500 «Внутренняя ошибка сервера». См. flask.Flask.handle_exception() для получения информации об этом поведении.

Если зарегистрирован обработчик ошибок для InternalServerError, он будет вызван. Начиная с Flask 1.1.0, этот обработчик ошибок всегда будет получать экземпляр InternalServerError, а не исходную необработанную ошибку. Исходная ошибка доступна как e.original_exception. До Werkzeug 1.0.0 этот атрибут существовал только во время необработанных ошибок, используйте getattr для доступа к нему в целях совместимости.

@app.errorhandler(InternalServerError)
def handle_500(e):
    original = getattr(e, "original_exception", None)

    if original is None:
        # direct 500 error, such as abort(500)
        return render_template("500.html"), 500

    # wrapped unhandled error
    return render_template("500_unhandled.html", e=original), 500

Ведение журнала

См. Ведение журнала для получения информации о том, как регистрировать исключения, например, отправляя их по электронной почте администраторам.

© 2007–2020 Pallets
Licensed under the BSD 3-clause License.
https://flask.palletsprojects.com/en/1.1.x/errorhandling/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API