REST框架视图中的异常处理

REST框架的视图处理各种异常,并处理返回适当的错误响应。

处理的异常是:

  • APIException在REST框架内部引发的子类。
  • Django的Http404例外。
  • Django的PermissionDenied例外。

在每种情况下,REST框架都会返回带有适当状态代码和内容类型的响应。响应的正文将包括有关错误性质的任何其他详细信息。

大多数错误响应都将detail在响应的主体中包含一个键。

例如,以下请求:

  1. DELETE http://api.example.com/foo/bar HTTP/1.1
  2. Accept: application/json

可能收到错误响应,指示DELETE该资源上不允许使用该方法:

  1. HTTP/1.1 405 Method Not Allowed
  2. Content-Type: application/json
  3. Content-Length: 42
  4. {"detail": "Method 'DELETE' not allowed."}

验证错误的处理方式略有不同,并且将字段名称作为响应中的键。如果验证错误不是特定于特定字段的,则它将使用“ non_field_errors”键,或为该NON_FIELD_ERRORS_KEY设置设置的任何字符串值。

任何示例验证错误可能看起来像这样:

  1. HTTP/1.1 400 Bad Request
  2. Content-Type: application/json
  3. Content-Length: 94
  4. {"amount": ["A valid integer is required."], "description": ["This field may not be blank."]}

自定义异常处理

您可以通过创建处理程序函数来实现自定义异常处理,该处理函数将API视图中引发的异常转换为响应对象。这使您可以控制API使用的错误响应的样式。

该函数必须带有一对参数,第一个是要处理的异常,第二个是包含任何额外上下文(例如当前正在处理的视图)的字典。异常处理程序函数应该返回一个Response对象,或者None在无法处理异常的情况下返回。如果处理程序返回None,则将重新引发异常,并且Django将返回标准的HTTP 500“服务器错误”响应。

例如,您可能要确保所有错误响应都在响应的主体中包括HTTP状态代码,如下所示:

  1. HTTP/1.1 405 Method Not Allowed
  2. Content-Type: application/json
  3. Content-Length: 62
  4. {"status_code": 405, "detail": "Method 'DELETE' not allowed."}

为了更改响应的样式,您可以编写以下自定义异常处理程序:

  1. from rest_framework.views import exception_handler
  2. def custom_exception_handler(exc, context):
  3. # Call REST framework's default exception handler first,
  4. # to get the standard error response.
  5. response = exception_handler(exc, context)
  6. # Now add the HTTP status code to the response.
  7. if response is not None:
  8. response.data['status_code'] = response.status_code
  9. return response

默认处理程序不使用context参数,但是如果异常处理程序需要更多信息(例如,当前正在处理的视图)(可以通过访问该信息),该参数将很有用context['view']

还必须使用EXCEPTION_HANDLER设置键在您的设置中配置异常处理程序。例如:

  1. REST_FRAMEWORK = {
  2. 'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler'
  3. }

如果未指定,则该'EXCEPTION_HANDLER'设置默认为REST框架提供的标准异常处理程序:

  1. REST_FRAMEWORK = {
  2. 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'
  3. }

请注意,将仅针对由引发的异常生成的响应调用异常处理程序。它不会用于视图直接返回的任何响应,例如,HTTP_400_BAD_REQUEST序列化程序验证失败时通用视图返回的响应。


API参考

APIException

签名: APIException()

在类或中引发的所有异常的基类APIView``@api_view

为了提供一个自定义异常,子类APIException和设置.status_code.default_detail以及default_code对类属性。

例如,如果您的API依赖于有时可能无法访问的第三方服务,则您可能希望实现“ 503 Service Unavailable” HTTP响应代码的异常。您可以这样做:

  1. from rest_framework.exceptions import APIException
  2. class ServiceUnavailable(APIException):
  3. status_code = 503
  4. default_detail = 'Service temporarily unavailable, try again later.'
  5. default_code = 'service_unavailable'

检查API异常

有许多不同的属性可用于检查API异常的状态。您可以使用它们为您的项目构建自定义异常处理。

可用的属性和方法是:

  • .detail -返回错误的文字描述。
  • .get_codes() -返回错误的代码标识符。
  • .get_full_details() -返回文字说明和代码标识符。

在大多数情况下,错误详细信息将很简单:

  1. >>> print(exc.detail)
  2. You do not have permission to perform this action.
  3. >>> print(exc.get_codes())
  4. permission_denied
  5. >>> print(exc.get_full_details())
  6. {'message':'You do not have permission to perform this action.','code':'permission_denied'}

在验证错误的情况下,错误详细信息将是项目的列表或字典:

  1. >>> print(exc.detail)
  2. {"name":"This field is required.","age":"A valid integer is required."}
  3. >>> print(exc.get_codes())
  4. {"name":"required","age":"invalid"}
  5. >>> print(exc.get_full_details())
  6. {"name":{"message":"This field is required.","code":"required"},"age":{"message":"A valid integer is required.","code":"invalid"}}

解析错误

签名: ParseError(detail=None, code=None)

在访问时请求包含格式错误的数据时引发request.data

默认情况下,此异常导致响应的HTTP状态代码为“ 400 Bad Request”。

验证失败

签名: AuthenticationFailed(detail=None, code=None)

当传入请求包含不正确的身份验证时引发。

默认情况下,此异常会导致HTTP状态码为“ 401未经身份验证”的响应,但也可能会导致“ 403禁止访问”响应,具体取决于所使用的身份验证方案。有关更多详细信息,请参见身份验证文档

未认证

签名: NotAuthenticated(detail=None, code=None)

当未经身份验证的请求未通过权限检查时引发。

默认情况下,此异常会导致HTTP状态码为“ 401未经身份验证”的响应,但也可能会导致“ 403禁止访问”响应,具体取决于所使用的身份验证方案。有关更多详细信息,请参见身份验证文档

没有权限

签名: PermissionDenied(detail=None, code=None)

在通过身份验证的请求未通过权限检查时引发。

默认情况下,此异常导致响应的HTTP状态代码为“ 403 Forbidden”。

未找到

签名: NotFound(detail=None, code=None)

在给定URL上不存在资源时引发。此异常等效于标准Http404Django异常。

默认情况下,此异常导致响应的HTTP状态代码为“ 404 Not Found”。

方法不被允许

签名: MethodNotAllowed(method, detail=None, code=None)

在未映射到视图上的处理程序方法的传入请求发生时引发。

默认情况下,此异常导致响应的HTTP状态代码为“ 405 Method Not Allowed”。

不能接受的

签名: NotAcceptable(detail=None, code=None)

当传入请求发生且Accept任何可用渲染器均无法满足的标头时引发。

默认情况下,此异常导致响应的HTTP状态代码为“ 406 Not Acceptable”。

不支持的媒体类型

签名: UnsupportedMediaType(media_type, detail=None, code=None)

在访问时没有解析器可以处理请求数据的内容类型时引发request.data

默认情况下,此异常导致响应的HTTP状态代码为“ 415不支持的媒体类型”。

节流的

签名: Throttled(wait=None, detail=None, code=None)

当传入请求未通过节流检查时引发。

默认情况下,此异常导致响应的HTTP状态代码为“ 429 Too Many Requests”。

验证错误

签名: ValidationError(detail, code=None)

ValidationError异常是从其他略有不同的APIException类别:

  • detail参数是强制性的,不是可选的。
  • 所述detail参数可以是错误的详细信息列表或字典,并且还可以是嵌套的数据结构。
  • 按照惯例,您应该导入序列化器模块并使用完全限定的ValidationError样式,以便将其与Django的内置验证错误区分开。例如。raise serializers.ValidationError('This field must be an integer value.')

ValidationError级应该用于串行和现场验证,以及验证器类。serializer.is_valid使用raise_exception关键字参数调用时也会引发此错误:

  1. serializer.is_valid(raise_exception=True)

通用视图使用该raise_exception=True标志,这意味着您可以在API中全局覆盖验证错误响应的样式。为此,请使用自定义异常处理程序,如上所述。

默认情况下,此异常导致响应的HTTP状态代码为“ 400 Bad Request”。


通用错误视图

Django REST框架提供了两个错误视图,适合提供通用的JSON500服务器错误和 400错误请求响应。(Django的默认错误视图提供HTML响应,这可能不适用于仅API的应用程序。)

根据Django的自定义错误视图文档中的说明使用它们。

rest_framework.exceptions.server_error

返回带有状态码500application/json内容类型的响应。

设置为handler500

  1. handler500 = 'rest_framework.exceptions.server_error'

rest_framework.exceptions.bad_request

返回带有状态码400application/json内容类型的响应。

设置为handler400

  1. handler400 = 'rest_framework.exceptions.bad_request'