Django ajax 错误响应最佳实践

Posted

技术标签:

【中文标题】Django ajax 错误响应最佳实践【英文标题】:Django ajax error response best practice 【发布时间】:2012-04-05 12:53:18 【问题描述】:

我在我的 Django 项目中使用 ajax 来改善用户体验。我关心的是如何正确响应浏览器的错误。据我所知,我可以:

    逐条验证请求数据,逐条防范异常。如果发生了不好的事情,请引发 Http404 或其他异常以明确宣布发生了错误。或者 只需编写没有异常处理的代码并假设它会工作。如果发生不好的事情,未捕获的异常会导致内部服务器错误,这仍然是浏览器的错误

对我来说,第一种方法似乎更正统,因为在 Python 中“显式优于隐式”的理念非常重要。但是由于从第二个中删除了各种异常检查,因此它更干净,更少碎片且更具可读性。

我正在使用 jQuery 来处理 ajax 请求/响应,这两种方法似乎都有效。我的问题是:

    这两种方法都可以接受吗? 第二种方法对其他 javascript 库是否会失败? 对此的最佳做法是什么?

PS。我做必要的数据验证。请不要因此而偏离主题。 :)

【问题讨论】:

您应该将其中一个答案标记为正确,并为对您有帮助的答案投票。如果您打算继续使用本网站,这是一种很好的做法,也是对那些花时间回答您的人的一种良好姿态:) @Sid 感谢您的指导 :)。我认为我的问题尚未完全回答(但无论如何我现在已经选择了最佳答案)。真的很抱歉,但我的声誉不足以支持投票。 如果您的问题没有得到完全回答,您不必选择最佳答案。抱歉不是故意催你的:) 【参考方案1】:

如果您返回状态码为 4xx 或 5xx 的响应,则这是一个错误,将触发 jQueries error 处理程序。虽然每次都可以简单地返回状态 200 并在 JSON 响应中使用“错误”字段(如 dm03514 建议的那样),但这有两个原因是不好的:

    它违反了良好的 HTTP 实践。 原因定义了很多错误代码

    你不能使用 jQuery 已经有一个错误处理程序的事实,它可以让你将正常行为与错误处理分开。

大多数时候错误响应与非错误响应有很大的不同所以将这些消息的处理放在一段 JS 代码中是没有意义的。因此,总而言之,使用状态为 200 的 JSON 响应作为您的正常响应,并返回(适当的!)4xx/5xx 响应以表示错误。这些也可以携带 JSON 有效负载,因此您的服务器端可以添加有关错误的其他详细信息。

【讨论】:

非常感谢您的澄清。所以实际上,我应该使用HttpResponse 的子类,例如HttpResponseNotFound,通知浏览器端发生了不好的事情并按预期触发error处理程序,对吧?【参考方案2】:

在我看来:

    第二种方法不可接受。 它不会失败,因为服务器仍然会发送一个 http 响应。 让我告诉你我在项目中做了什么:

当我的项目开始时,我总是在文件夹结构的顶部预先添加一个名为errors的模块,首先我会编写一个继承自Exception的基本异常类,然后写出一些常见的异常类,如@ 987654323@, 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
        ....

上面的代码是我在项目中如何处理异常的总结,总的来说,它是关于准确的异常控制、正确的异常分类,当然还有“显式优于隐式”的理念。

===更新=== 至于ajax中如何处理对应的响应,可以使用jquery1.5中的新特性statusCode

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

来自 jquery 文档:

数字 HTTP 代码和函数的映射,当 响应有相应的代码。例如,以下将 响应状态为 404 时发出警报

【讨论】:

感谢您的解决方案。对常见错误进行分类并使用中间件处理它们似乎是一种简洁且可扩展的解决方案。这种方法常用吗? 好吧,设计自定义异常是编写健壮程序的建议方法,至于 Django,我不确定这是否是最佳解决方案,因为我有一段时间没有使用它。但是Django仍然是python,如果你认为这种方式是pythonic,它就可以了。【参考方案3】:

我无法回答这两种方法是否都可以接受,只能告诉你我在做什么。在我看来,我发现了一些特定/明确的错误,例如:

帖子中的参数无效或缺失 高级错误,例如数据库中已存在用户名(例如在注册情况下) 所有其他系统错误

我认为,如果您将错误归类为用户必须知道的一些特定错误,然后是其他所有错误,那么您的代码最多将返回 2 或 3 个错误路由,恕我直言,这还不错。 我使用 JSON 返回错误,我的结构通常是这样的:

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

显然这是非常基本的,但希望能给你一个大致的概念。我建议不要让用户看到系统生成的内部服务器错误。这是糟糕的用户体验,即使对于内部应用也是如此。

希望这会有所帮助。

【讨论】:

阅读了答案后,我开始明白达到相同的效果并不能证明我的方法(第二种方法)是正确的。谢谢!【参考方案4】:

我不会采用您建议的任何方法。我会建议一些类似于 Sid 所说的内容。为什么不想编写无错误代码?

我会尝试解决我一直编写的代码中所有可能的错误和错误。这包括验证用户输入。使用 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 回调中确保响应有效,如果它没有提醒用户他们做错了什么。不要让他们挂着你正在为他们制作应用程序!

【讨论】:

我明白你的意思。但是是否有任何 explicit 方法来触发 jQuery.ajax 的错误参数?我想当请求真正成功时调用成功参数。【参考方案5】:

使用选项 1,但不完全按照您描述的方式,您应该返回一个带有 status_code 200 的 HttpResponse,在响应内容(使用 JSON 或一些文本)中指示发生了验证错误,然后,当您在使用 JQuery 的客户端只需检查响应内容并检测是否存在验证错误。

HttpResponse 的 JSON 字符串示例:

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

选项 2 不是一个好的做法,因为当服务器抛出未捕获的异常并且程序员通常不知道时,就会发生内部服务器错误。

不要使用 HTTP 状态码来表示验证错误,这不是他们的目的。

【讨论】:

感谢您的建议。但是如果我在示例中像这样返回 HttpResponse,就会调用 jQuery.ajax 的成功函数,对吗?我只是想知道错误函数是干什么用的? 是的,成功函数将被调用。在 JQuery documentation 中说:如果请求失败,则会按照注册顺序调用错误回调。,因此如果请求发生错误,则只会触发错误处理程序请求中发送的信息。

以上是关于Django ajax 错误响应最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

Django 查看安全性和最佳实践

Django - 异常处理最佳实践和发送自定义错误消息 [关闭]

从 Spring 控制器方法发送 Json 响应的最佳实践

转 Web程序优化的最佳实践(网站内容篇)

Celery学习--- Celery 最佳实践之与django结合实现异步任务

Ticker 的 EaselJS 的最佳实践是啥