Django-异常处理最佳实践并发送自定义错误消息 [英] Django - exception handling best practice and sending customized error message

查看:130
本文介绍了Django-异常处理最佳实践并发送自定义错误消息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我开始考虑在我的Django应用程序中进行适当的异常处理,我的目标是使它尽可能地易于使用.出于用户友好的目的,我暗示用户必须始终对确切的错误之处有详细的说明. 在这篇文章之后,最佳做法是

I am starting to think about appropriate exception handling in my Django app, and my goal is to make it as user-friendly, as possible. By user-friendliness, I imply that the user must always get a detailed clarification as to what exactly went wrong. Following on this post, the best practice is to

使用状态为200的JSON响应进行常规响应, 返回错误的(适当的!)4xx/5xx响应.这些可以携带 JSON有效负载也是如此,因此您的服务器端可以添加其他详细信息 关于错误.

use a JSON response with status 200 for your normal responses and return an (appropriate!) 4xx/5xx response for errors. These can carry JSON payload, too, so your server side can add additional details about the error.

我试图用这个答案中的关键词搜索谷歌,但我的脑子里仍然有比答案更多的问题.

I tried to google by the key words in this answer, by still have more questions than answers in my head.

  1. 如何确定返回哪个错误代码-400或500?我的意思是,Django有许多预定义的错误类型,如何在Django异常类型和400-500错误代码之间实现这种映射,以使异常处理块尽可能地干燥和可重用?
  2. @reorx在帖子中建议的使用中间件的方法认为可行吗? (答案只有一次投票,因此我不愿钻研细节并在我的项目中实现它
  3. 最重要的是,有时我可能会提出与业务逻辑相关的错误,而不是错误的语法或诸如空值之类的标准.例如,如果我的法人实体中没有CEO,我可能想禁止用户添加合同.在这种情况下,错误状态应该是什么?如何对用户进行详细的错误解释以引发错误?
  1. How do I decide upon which error code - 400 or 500 - to return? I mean, Django has many predefined error types, and how can I implement this mapping between Django exception types and 400-500 error code to make the exception handling blocks as DRY and reusable as possible?
  2. Can the approach with middleware suggested by @Reorx in the post be considered viable ? ( The answer got only one upvote, thus making me reluctant to delve into details and implement it in my project
  3. Most importantly, sometimes I may wish to raise an error related to business logic, rather than incorrect syntax or something standard like null value. For example, if there's no CEO in my legal entity, I might want to prohibit the user from adding a contract. What should be the error status in this case, and how do I throw an error with my detailed explanation of the error for the user?

让我们从简单的角度考虑它

Let us consider it on a simple view

def test_view (request):

   try:
          # Some code .... 
          if my_business_logic_is_violated():
              # How do I raise the error
              error_msg = "You violated bussiness logic because..."
              # How do I pass error_msg 
          my_response = {'my_field' : value}
  except ExpectedError as e:
          # what is the most appropriate way to pass both error status and custom message
          # How do I list all possible error types here (instead of ExpectedError to make the exception handling block as DRY and reusable as possible
      return JsonResponse({'status':'false','message':message}, status=500)

推荐答案

首先,您应该考虑要暴露哪些错误:

First of all you should think on what errors you want to expose:

  • 通常会披露4xx错误(归因于客户端的错误),以便用户可以更正请求.

  • Usually 4xx errors (Errors that are attributed to the client-side) are disclosed so the user may correct the request.

另一方面,通常仅在没有信息的情况下显示5xx错误(归因于服务器端的错误).我认为对于这些用户,您应该使用哨兵之类的工具来监视和解决此错误,这可能存在安全问题嵌入其中.

On the other side, 5xx errors (Errors that are attributed to the server-side) are usually only presented without information. In my opinion for those you should use tools like Sentry do monitor and resolve this errors, that may have security issues embedded in them.

在我看来,对于正确的Ajax请求,您应该返回一个状态码,然后返回一些json以帮助理解消息和解释(如果适用)之类的情况.

Having this is mind in my opinion for a correct Ajax request you should return a status code and then some json to help understand what happened like a message and an explanation (when applicable).

如果您的目标是使用Ajax提交信息,建议您设置表单满足您的需求.这样,您就可以轻松地通过一些验证过程.在示例中,我将假设情况是这样.

If your objective is to use ajax to submit information I suggest setting a form for what you want. This way you get past some of the validation process with ease. I will assume the case is this in the example.

第一-请求正确吗?

def test_view(request):
    message = None
    explanation = None
    status_code = 500
    # First, is the request correct?
    if request.is_ajax() and request.method == "POST":
        ....
    else: 
        status_code = 400
        message = "The request is not valid."
        # You should log this error because this usually means your front end has a bug.
        # do you whant to explain anything?
        explanation = "The server could not accept your request because it was not valid. Please try again and if the error keeps happening get in contact with us."

    return JsonResponse({'message':message,'explanation':explanation}, status=status_code)

第二-表单中是否存在错误?

Second - Are there errors in the form?

form = TestForm(request.POST)
if form.is_valid():
    ...
else:
    message = "The form has errors"
    explanation = form.errors.as_data()
    # Also incorrect request but this time the only flag for you should be that maybe JavaScript validation can be used.
    status_code = 400

您甚至可能逐字段获取错误,因此可以更好地在表单本身中进行显示.

You may even get error field by field so you may presented in a better way in the form itself.

第三-让我们处理请求

        try:
            test_method(form.cleaned_data)
        except `PermissionError` as e:
            status_code= 403
            message= "Your account doesn't have permissions to go so far!"
        except `Conflict` as e:
            status_code= 409
            message= "Other user is working in the same information, he got there first"
        ....
        else:
            status_code= 201
            message= "Object created with success!"

根据您定义的异常,可能需要不同的代码.转到维基百科并检查列表. 不要忘记,响应在代码中也会有所不同.如果将某些内容添加到数据库中,则应返回201.如果您只是获得信息,那么您正在寻找GET请求.

Depending on the exceptions you define, different codes may be required. Go to Wikipedia and check the list. Don't forget that response also vary in code. If you add something to the database you should return a 201. If you just got information then you were looking for a GET request.

回答问题

  1. 如果不处理,Django异常将返回500个错误,因为如果您不知道会发生异常,那么这是服务器中的错误.除了404和登录要求外,我将对所有内容执行try catch块. (对于404,您可以提高它,如果您执行@login_required或所需的权限,django会在不执行任何操作的情况下以适当的代码进行响应.)

  1. Django exceptions will return 500 errors if not dealt with, because if you don't know that an exception is going to happen then it is an error in the server. With exception to 404 and login requirements I would do try catch blocks for everything. (For 404 you may raise it and if you do @login_requiredor a permission required django will respond with the appropriate code without you doing anything).

我不同意这种方法.正如您所说的,错误应该是明确的,因此您应该始终了解应该发生的情况以及如何解释错误,并使错误取决于所执行的操作.

I don't agree completely to the approach. As you said errors should be explicit so you should know allways what is suppose to happen and how to explain it, and make it dependable on the operation performed.

我会说400错误是可以的.这只是一个不好的要求,您只需要解释为什么,错误代码既适合您又适合您的js代码,因此请保持一致.

I would say a 400 error is ok for that. It is a bad request you just need to explain why, the error code is for you and for your js code so just be consistent.

(提供示例)-在text_view中,您应该像第三个示例中那样具有test_method.

(example provided) - In the text_view you should have the test_method as in the third example.

测试方法应具有以下结构:

Test method should have the following structure:

def test_method(validated_data):
    try: 
        my_business_logic_is_violated():
    catch BusinessLogicViolation:
        raise
    else:
        ... #your code

在我的示例中:

   try:
        test_method(form.cleaned_data)
    except `BusinessLogicViolation` as e:
        status_code= 400
        message= "You violated the business logic"
        explanation = e.explanation
   ...

我认为违反业务逻辑是一个客户端错误,因为如果在该请求之前需要进行某些操作,客户端应该意识到这一点,并要求用户先执行此操作. (摘自错误定义):

I considered the business logic violation to be a Client Error because if something is needed before that request the client should be aware of that and ask the user to do it first. (From the Error Definition):

400(错误请求)状态代码表示服务器无法执行以下操作: 由于某些原因,将不会处理该请求 客户端错误(例如格式错误的请求语法,无效的请求
邮件框架或欺骗性请求路由).

The 400 (Bad Request) status code indicates that the server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request
message framing, or deceptive request routing).

顺便说一句,您可以在用户-上看到 Python文档定义的异常,因此您可以提供适当的错误消息.此示例的根据是,您根据生成消息的位置在my_business_logic_is_violated()中引发带有不同消息的BusinessLogicViolation异常.

By the way, you can see the Python Docs on User-defined Exceptions so you may give appropriate error messages. The idea behind this example is that you raise a BusinessLogicViolationexception with a different message in my_business_logic_is_violated()according to the place where it was generated.

这篇关于Django-异常处理最佳实践并发送自定义错误消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆