【djangorestframework】13、Exceptions(异常)

异常(Exceptions)

  • 异常...允许错误处理在程序结构的中心或者高级的地方被清晰有条理的组织起来。---Doug Hellmann, python异常处理技术

REST framework视图中的异常处理(Exception handling in REST framework views)

  • REST framework的视图处理各种异常,并处理返回适当的错误响应。
  • 处理的异常有
    • 在REST framework内引发的APIException的子类。
    • Django的Http404异常
    • Django的PermissionDenied异常
  • 针对每种情况,REST framework将返回具有适当的状态码和内容类型的响应。响应的主体将包含有关错误性质的任何其他细节。
  • 大多数错误响应将包括响应正文中的detail键
  • 例如,如下请求:
DELETE http://api.example.com/foo/bar HTTP/1.1
Accept: application/json
  • 可能会收到一个错误响应,指示在该资源上不允许DELETE方法:
HTTP/1.1 405 Method Not Allowed
Content-Type: application/json
Content-Length: 42

{"detail": "Method 'DELETE' not allowed."}
  • 验证错误的处理方式稍有不同,并将字段名称作为响应中的键。如果验证错误没有指定特定字段,那么它将使用"non_field_error"键,或者为NON_FIELD_ERRORS_KEY setting中设置的任何字符串值
  • 任何示例验证错误可能如下所示:
HTTP/1.1 400 Bad Request
Content-Type: application/json
Content-Length: 94
{"amount": ["A valid integer is required."], "description": ["This field may not be blank."]}

自定义异常处理(Custom exception handling)

  • 你可以通过创建处理程序函数来实现自定义异常处理。该函数将API视图中引发的异常转换为响应对象。这允许你控制API使用的错误响应的样式。
  • 该视图必须带有一对参数,第一个是要处理的异常,第二个是包含任何额外上下文的字典,例如当前正在处理的视图。异常处理程序函数应返回Response对象,或者如果无法处理异常,则返回None。如果处理程序返回None,那么异常将被重新引发,Django将返回一个标准的HTTP 500'server error'响应。
  • 例如,你可能希望确保所有错误响应都包含响应正文中的HTTP状态代码,如下所示:
HTTP/1.1 405 Method Not Allowed
Content-Type: application/json
Content-Length: 62

{"status_code": 405, "detail": "Method 'DELETE' not allowed."}
  • 为了改变响应的样式,你可以编写如下自定义异常处理程序:
from rest_framework.views import exception_handler

def custom_exception_handler(exc, context):
    # Call REST framework's default exception handler first,
    # to get the standard error response.
    response = exception_handler(exc, context)

    # Now add the HTTP status code to the response.
    if response is not None:
        response.data['status_code'] = response.status_code

    return response
  • 默认处理程序不使用上下文参数,但如果异常处理程序需要诸如当前正在处理的视图之类的进一步信息,这可能很有用,这可以作为context['view']访问
  • 异常处理程序还必须使用EXCEPTION_HANDLER设置键在你设置中进行配置。例如:
REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler'
}
  • 如果未指定,则'EXCEPTION_HANDLER'设置默认为由REST famework提供的标准异常处理程序:
REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'
}
  • 请注意,异常处理程序仅由异常引发生成的响应调用。它不会用于视图直接返回的任何响应例如当序列化器验证失败时通用视图返回的HTTP_400_BAD_REQUEST响应

API参考(API Reference)

APIException

  • 签名: APIException()
  • APIView类或@api_view中引发的所有异常的基类。
  • 要提供自定义异常,请继承APIException,并在该类上设置.status_code,.default_detail和default_code属性。
  • 例如,如果你的API依赖于有时可能无法访问的第三方服务,则可能希望为"503 Service Unavailable"HTTP响应码实现异常。你可以这样做:
from rest_framework.exceptions import APIException

class ServiceUnavailable(APIException):
    status_code = 503
    default_detail = 'Service temporarily unavailable, try again later.'
    default_code = 'service_unavailable'
  • 检查API异常(Inspecting API exceptions)
    • 有许多不同的属性可用于检查API异常的状态。你可以使用它们为项目构建自定义处理程序。
    • 可用的属性和方法是:
      • .detail--返回错误的文门描述
      • .get_codes() --返回错误的代码标识符
      • .get_full_details() --返回文本描述和代码标识符
    • 在大多数情况下,错误细节将是一个简单的项:
>>> print(exc.detail)
You do not have permission to perform this action.
>>> print(exc.get_codes())
permission_denied
>>> print(exc.get_full_details())
{'message':'You do not have permission to perform this action.','code':'permission_denied'}
    • 在验证错误的情况下,错误详情将是项列表或字典:
>>> print(exc.detail)
{"name":"This field is required.","age":"A valid integer is required."}
>>> print(exc.get_codes())
{"name":"required","age":"invalid"}
>>> print(exc.get_full_details())
{"name":{"message":"This field is required.","code":"required"},"age":{"message":"A valid integer is required.","code":"invalid"}}

ParseError

  • 签名:ParseError(detail=None, code=None)
  • 如果请求在访问request.data时包含格式错误的数据,则引发此异常。
  • 默认情况下,此异常会导致HTTP状态码"400 Bad Request"的响应

AuthenticationFailed

  • 签名:AuthenticationFailed(detail=None, code=None)
  • 当传入请求包含不正确的身份验证时引发
  • 默认情况下,此异常会导致HTTP状态码"401 Unauthenticated"的响应,但它也可能导致"403 Forbidden"的响应,具体取决于所使用的身份验证方案。有关详细信息,请参阅身份验证文档.

NotAuthenticated

  • 签名:NotAuthenticated(detail=None, code=None)
  • 未经身份验证的请求未通过权限检查时引发
  • 默认情况下,此异常会导致HTTP状态码"401 Unauthenticated"的响应,但它也可能导致"403 Forbidden"的响应,具体取决于所使用的身份验证方案。有关详细信息,请参阅身份验证文档。

PermissionDenied

  • 签名:PermissionDenied(detail=None, code=None)
  • 当经过身份验证的请求未通过权限检查时引发。
  • 默认情况下,此异常会导致HTTP状态码为"403 Forbidden"的响应。

NotFound

  • 签名:NotFound(detail=None, code=None)
  • 当资源不存在时给定的URL时引发。该异常相当于标准的Http404  Django异常。
  • 默认情况下,此异常会导致HTTP状态码"404 Not Found"的响应。
MethodNotAllowed
  • 签名:MethodNotAllowed(Method, detail=None, code=None)
  • 当传入请求发生,但未映射到视图上的处理程序方法时引发。
  • 默认情况下,此异常会导致HTTP状态代码"405 Method Not Allowed"的响应。

NotAcceptable

  • 签名:NotAcceptable(detail=None, code=None)
  • 当传入请求的Accept标头不能被任何可用的渲染器满足时引发。
  • 默认情况下,此异常会导致HTTP状态码为"406 Not Acceptable"的响应。

UnsupportedMediaType

  • 签名:UnsupportedMediaType(media_type, detail=None, code=None)
  • 如果在访问request.data时没有可以处理请求数据的内容类型的解析器,则引发。
  • 默认情况下,此异常会导致HTTP状态码为"415 Unsupported Media Type"的响应

Throttled

  • 签名:Throttled(wait=None, detail=None, code=None)
  • 当传入请求未通过限制检查时引发
  • 默认情况下,此异常会导致HTTP状态码"429 Too Many REquests"的响应。

ValidationError

  • 签名:ValidationError(detail, code=None)
  • ValidationError异常与其他APIException类略有不同:
    • detail参数是必需的,不是可选的。
    • detail参数可以是错误详情列表或字典,也可以是嵌套的数据结构。
    • 按照惯例,你应该导入serializers模块并使用完全限定的ValidationError样式,用以区别Django的内置验证错误。例如:raise serializers.ValidationError('this field must be an integer value .')
  • ValidationError类应用于序列化器和字段验证以及验证器类。在调用serializer.is_valid时使用raise_exception关键字参数也会引发:
serializer.is_valid(raise_exception=True)
  • 通用视图使用raise_exception=True标志,这意味着你可以在API中全局覆盖验证错误响应的样式。为此,请使用自定义异常处理程序,如上所述。
  • 默认情况下,此异常会导致HTTP状态码为"400 Bad Request"的响应。

通用错误视图(Generic Error Views)

  • Django REST Framework提供了两个错误视图,适用于提供通用JSON 500 Server Error和400 Bad Request响应。(Django 的默认错误视图提供HTML响应,这可能不适合仅限API应用程序。)
  • 按照Django的自定义错误视图文档使用它们
rest_framework.exceptions.server_error
  • 返回状态码为500且application/json内容类型的响应。
  • 设为handler500:
handler500 = 'rest_framework.exceptions.server_error'
rest_framework.exceptions.server_error
  • 返回状态码为400且application/json内容类型的响应
  • 设为handler400
handler400 = 'rest_framework.exceptions.bad_request'
posted @ 2022-04-25 16:10  郭祺迦  阅读(353)  评论(0)    收藏  举报