异常 (Exceptions)

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

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

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

处理的异常有:

  • 在 REST framework 内引发的 APIException 的子类。
  • Django 的 Http404 异常。
  • Django 的 PermissionDenied 异常。

针对每种情况,REST framework 将返回具有适当的状态码和内容类型的响应。响应的主体将包含有关错误性质的任何其他细节。

大多数错误响应将包括响应正文中的 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 setting 中设置的任何字符串值。

任何示例验证错误可能如下所示:

  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."]}

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

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

该函数必须带有一对参数,第一个是要处理的异常,第二个是包含任何额外上下文的字典,例如当前正在处理的视图。异常处理程序函数应返回 Response 对象,或者如果无法处理异常,则返回 None。如果处理程序返回 None,那么异常将被重新引发,Django 将返回一个标准的 HTTP 500 ‘server error’ 响应。

例如,您可能希望确保所有错误响应都包含响应正文中的 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['view'] 访问。

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

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

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

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

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


API 参考 (API Reference)

APIException

签名APIException()

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

要提供自定义异常,请继承 APIException,并在该类上设置 .status_code.default_detaildefault_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 异常 (Inspecting API exceptions)

有许多不同的属性可用于检查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

签名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 关键字参数也会引发:

  1. 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

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

设为 handler500

  1. handler500 = 'rest_framework.exceptions.server_error'

rest_framework.exceptions.server_error

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

设为 handler400

  1. handler400 = 'rest_framework.exceptions.bad_request'