异常
异常处理…允许错误处理在程序结构的中心或者高层级的地方被清晰有条理的组织起来。
Exceptions… allow error handling to be organized cleanly in a central or high-level place within the program structure.
— Doug Hellmann, Python Exception Handling Techniques
Rest框架视图中的异常处理
Exception handling in REST framework views
REST框架的视图处理了各种异常,并正确地返回了错误响应。
REST framework’s views handle various exceptions, and deal with returning appropriate error responses.
被处理的异常有:
Rest框架内部抛出的APIException的子类。
Django的Http404异常。
Django的PermissionDenied异常
针对每种情况,REST框架将返回一个包含了正确的状态码和content-type的响应。响应体包含了任何关于错误本身的额外细节。
大部分的错误响应将在响应体中包含了一个detail的键。
例如下面请求:
DELETE http://api.example.com/foo/bar HTTP/1.1
Accept: application/json
你本文来源gao.dai.ma.com搞@代*码#网还可能接收到一个错误响应,表明对该资源DELETE方法不允许的。
HTTP/1.1 405 Method Not Allowed Content-Type: application/json Content-Length: 42 {"detail": "Method 'DELETE' not allowed."}
校验错误的处理有些轻微的不同,它会把字段的名字作为键包含进来。如果校验错误没有被指定到一个特定的字段,那么它会使用non_field_errors作为键,或者是你在setting文件中设定的NON_FIELD_ERRORS_KEY任意字符串的值。
任何校验错误将类似下面的形式:
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."]}
自定义异常处理
你可以实现你的自定义异常处理。可以通过创建一个异常处理函数将API视图中抛出的异常转换成响应对象。这样一来,你就可以控制你的API使用的错误响应格式。
这个异常处理函数必须传入两个参数,第一个是要处理的异常,第二个是一个包含了任何额外上下文信息(例如当前被处理的视图)的字典。该异常处理函数要么返回一个Response对象,要么在异常无法处理的时候返回None。如果返回了None,异常将会被重新抛出,最后Django会返回一个标准的HTTP 500 ‘服务器错误’的响应。
例如,你可能希望保证所有的错误响应体中都包含了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没有被默认的异常处理器使用,但是如果你需要更多的信息,例如你想获得当前被处理的视图,它就能给你援助之手了。通过context[‘view’]就可以获取当前视图。