Наилучшая практика ответа на ошибку в Django ajax

Я использую ajax для улучшения пользовательского интерфейса в своем проекте Django. Меня беспокоит, как правильно реагировать на ошибки в браузере. Насколько я знаю, я могу:

  • проверять данные запроса по частям и защищать исключение один за другим. Если произойдет что-то плохое, поднимите Http404 или другое исключение, чтобы явное объявление об ошибке произошло. Или
  • просто напишите код без обработки исключений и предположим, что он будет работать. Если произойдет что-то плохое, непокрытое исключение вызовет внутреннюю ошибку сервера, которая по-прежнему является ошибкой для браузера.

Для меня метод fisrt кажется более ортодоксальным, так как в Python действительно учитывается философия "Явная лучше, чем Implicit". Но поскольку все виды проверки исключений удаляются со второго, он более чистый, менее фрагментированный и более читаемый.

Я использую jQuery для обработки запроса/ответа ajax, и оба метода кажутся работающими. Мои вопросы:

  • Доступны ли оба метода?
  • Будет ли второй метод работать с другими библиотеками Javascript?
  • Какова наилучшая практика для этого?

PS. Я действительно делаю валидацию данных. Пожалуйста, не отклоняйтесь от темы для этого.:)

Ответ 1

Если вы вернете ответ с кодом состояния 4xx или 5xx, это будет ошибкой и вызовет обработчик jQueries error. Несмотря на то, что каждый раз возможно простое состояние возврата 200 и использовать поле "ошибка" в ответе JSON (например, предложенное dm03514), это плохо по двум причинам:

  • Это нарушает хорошую практику HTTP. Существует причина, по которой существует множество кодов ошибок

  • Вы не можете использовать тот факт, что jQuery уже имеет обработчик ошибок, который позволяет отделять нормальное поведение от обработки ошибок.

В большинстве случаев ответ об ошибке будет сильно отличаться от ответа без ошибок. Поэтому просто не нужно помещать обработку этих сообщений в один кусок кода JS. Итак, чтобы подвести итог, используйте ответ JSON со статусом 200 для ваших обычных ответов и верните ответ (соответствующий!) 4xx/5xx для ошибок. Они могут нести полезную нагрузку JSON, поэтому ваша серверная сторона может добавить дополнительные сведения об ошибке.

Ответ 2

По-моему:

  • второй метод неприемлем.
  • он не будет сбой, так как сервер все равно отправит ответ http.
  • Позвольте мне рассказать вам, что я делаю в своих проектах:

когда мой проект запускается, я всегда добавляю модуль с именем errors в верхней части структуры папок, во-первых, я напишу базовый класс Exception, который наследует от Exception, затем выписывает некоторые общие классы исключений, такие как ObjectNotFound, ValidationError из моего опыта. Когда я думаю, что в моем коде должно возникнуть исключение, я буду использовать исключения из этого модуля, и когда я найду новое исключение, которое нужно обработать, я напишу в нем новое исключение.

Затем это работа над тем, как обращаться с ними. Поскольку вы используете Django, очень легко перехватывать исключения через посредство, вы можете написать что-то вроде этого:

from youproject import errors

# categorize your exceptions
400_ERRORS = (errors.ValidationError, errors.ParametersMissing, )
403_ERRORS = (errors.AuthenticationError, )
404_ERRORS = (errors.ObjectNotFound, errors.ResourceNotExist, )

class ExceptionHandleMiddleware(object):
    def process_exception(self, request, e):
        # set status_code by category of the exception you caught
        if isinstance(e, 400_ERRORS):
            status_code = 400
        elif isinstance(e, 403_ERRORS):
            status_code = 403
        elif isinstance(e, 404_ERRORS):
            status_code = 404
        else:
            # if the exception not belone to any one you expected,
            # or you just want the response to be 500
            status_code = 500
            # you can do something like write an error log or send report mail here
            logging.error(e)

        response_dict = {
            'status': 'error',
            # the format of error message determined by you base exception class
            'msg': str(e)
        }
        if settings.debug:
            # you can even get the traceback infomation when you are in debug mode
            response_dict['traceback'] = traceback.format_exc()

        # set header and return the response
        ....

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

=== UPDATE === Когда дело доходит до того, как обрабатывать соответствующие ответы в ajax, вы можете использовать новую функцию в jquery1.5 statusCode:

$.ajax({
  statusCode: {
    404: function() {
      alert('page not found');
    }
  }
});

из документации jquery:

Карта числовых кодов и функций HTTP, которые будут вызываться, когда ответ имеет соответствующий код. Например, следующее когда статус ответа равен 404

Ответ 3

Я не могу ответить, приемлемы ли оба метода, но может только сказать вам, что я делаю. По моему мнению, я обнаруживаю некоторые конкретные/явные ошибки, такие как:

  • Недопустимые или отсутствующие параметры в сообщении
  • Ошибки высокого уровня, такие как имя пользователя, уже присутствующее в базе данных (например, в ситуации регистрации).
  • Все другие системные ошибки

Я думаю, что если вы классифицируете свои ошибки как некоторые конкретные ошибки, о которых должен знать пользователь, а затем все остальное, ваш код будет иметь не более двух или трех возвратов с маршрутами ошибок, что ИМХО не так уж плохо. Я использую JSON для возврата ошибок, и моя структура обычно такова:

respons={}
response["error|ok"]
response["msg"]="User not found"
response["type"]=ERROR_TYPE # only applicable for errors

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

Надеюсь, что это поможет.

Ответ 4

Я бы не взял ни один из предложенных вами подходов. Я бы предложил что-то вроде того, что сказал Сид. Почему вы не хотите писать код ошибки?

Я попытался бы устранить все возможные ошибки и ошибки в коде, который я пишу в любое время. Это включает проверку ввода пользователя. С ajax я думаю, что важно отправить сообщения обратно пользователю. Это легко выполнить с помощью json.

response_dict = {}
try:
   # do action that could cause an error
except ExpectedError as e:
   response_dict['success'] = False
   response_dict['message'] e.msg # or custom message
   return HttpResponse(json.dumps(repsonse_dict))

то в вашем обратном вызове ajax убедитесь, что ответ действителен, если он не предупреждает пользователя о том, что они сделали неправильно. не оставляйте их висящими, вы делаете приложение для них!

Ответ 5

Используйте параметр 1, но не полностью так, как вы его описываете, вы должны вернуть HttpResponse со статусом-кодом 200, указывающим в контенте ответа (используя JSON или какой-либо текст), что произошла ошибка проверки, а затем, когда вы обрабатываете ответ на клиент с JQuery просто проверяет содержимое ответа и обнаруживает, были ли ошибки проверки.

Пример строки JSON для HttpResponse:

{"errors": "true", "messages": ["Error #1", "Error #2", "etc."]}

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

Не используйте коды состояния HTTP для обозначения ошибок проверки, что не является их целью.