Наилучшая практика ответа на ошибку в 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 для обозначения ошибок проверки, что не является их целью.