官方原文連接
本系列文章 github 地址
轉載請註明出處python
REST framework 的視圖處理各類異常,並返回適當的錯誤響應。git
須要處理的異常狀況有:github
APIException
的子類。Http404
異常。PermissionDenied
異常。在每種狀況下,REST framework 都會返回一個帶有適當狀態碼和內容類型的響應。響應的主體將包含有關錯誤性質的其餘細節。django
大多數錯誤響應將包含響應正文中的關鍵 detail
。json
例如,如下請求:api
DELETE http://api.example.com/foo/bar HTTP/1.1
Accept: application/json
複製代碼
可能會收到錯誤響應,指出在該資源上不容許使用 DELETE
方法:bash
HTTP/1.1 405 Method Not Allowed
Content-Type: application/json
Content-Length: 42
{"detail": "Method 'DELETE' not allowed."}
複製代碼
驗證錯誤的處理方式稍有不一樣,但都是將字段名稱做爲響應中的關鍵字。若是驗證錯誤不是特定於某個字段的,那麼它將使用 「non_field_errors」 鍵,或者爲 NON_FIELD_ERRORS_KEY
setting 設置的字符串值。數據結構
示例驗證錯誤可能以下所示:app
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 錯誤響應的樣式。ide
該函數必須帶有一對參數,第一個是要處理的異常,第二個是包含任何額外上下文(例如當前正在處理的視圖)的字典。異常處理函數應該返回一個 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 參數不被默認處理程序使用,可是若是異常處理程序須要更多信息,例如當前正在處理的視圖(能夠做爲 context['view']
訪問),則該參數可能頗有用。
異常處理程序還必須使用 EXCEPTION_HANDLER
setting key 在你的設置中進行配置。例如:
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler'
}
複製代碼
若是未指定,則 'EXCEPTION_HANDLER'
setting 默認爲由 REST framework 提供的標準異常處理程序:
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'
}
複製代碼
請注意,異常處理程序只會根據由異常產生的響應調用。它不會用於視圖直接返回的任何響應,例如在序列化驗證失敗時通用視圖返回的 HTTP_400_BAD_REQUEST
響應。
簽名: 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 異常的狀態。你可使用它們爲你的項目構建自定義異常處理。
可用的屬性和方法有:
.detail
- 返回錯誤的文本描述。.get_codes()
- 返回錯誤的代碼標識符。.get_full_details()
- 返回文本描述和代碼標識符。在大多數狀況下,錯誤詳情將是一個簡單的 item:
>>> 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'}
複製代碼
在驗證錯誤的狀況下,錯誤詳情將是 item 列表或字典:
>>> 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(detail=None, code=None)
在訪問 request.data
時包含格式錯誤的數據則會引起此異常。
默認狀況下,此異常會致使 HTTP 狀態碼 "400 Bad Request" 的響應。
簽名: AuthenticationFailed(detail=None, code=None)
當傳入的請求包含不正確的身份驗證時引起。
默認狀況下,此異常會致使 HTTP 狀態碼 "401 Unauthenticated" 的響應,但也可能會致使 "403 Forbidden" 響應,具體取決於所使用的身份驗證方案。
簽名: NotAuthenticated(detail=None, code=None)
當未經身份驗證的請求未經過權限檢查時引起。
默認狀況下,此異常會致使 HTTP 狀態碼 "401 Unauthenticated" 的響應,但也可能會致使 "403 Forbidden" 響應,具體取決於所使用的身份驗證方案。
簽名: PermissionDenied(detail=None, code=None)
當通過身份驗證的請求未經過權限檢查時引起。
默認狀況下,此異常會致使 HTTP 狀態碼 "403 Forbidden" 的響應。
簽名: NotFound(detail=None, code=None)
當資源不存在於給定的 URL 時引起。這個異常至關於標準的 Http404
Django 異常。
默認狀況下,此異常會致使 HTTP 狀態碼爲 "404 Not Found" 的響應。
簽名: MethodNotAllowed(method, detail=None, code=None)
當請求發生時,找不到視圖上對應的處理方法時引起。
默認狀況下,此異常會致使 HTTP 狀態碼爲 "405 Method Not Allowed" 的響應。
簽名: NotAcceptable(detail=None, code=None)
當請求發生時,任何可用渲染器都不符合 Accept
header 時引起。
默認狀況下,此異常會致使 HTTP 狀態碼爲 "406 Not Acceptable" 的響應。
簽名: UnsupportedMediaType(media_type, detail=None, code=None)
若是在訪問 request.data
時沒有能夠處理請求數據的內容類型的解析器,就會引起。
默認狀況下,此異常會致使 HTTP 狀態碼 "415 Unsupported Media Type" 的響應。
簽名: 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
類應該用於序列化類和字段驗證以及驗證器類。使用 raise_exception
關鍵字參數調用 serializer.is_valid
時也會引起此問題:
serializer.is_valid(raise_exception=True)
複製代碼
通用視圖使用 raise_exception=True
標誌,意味着你能夠在 API 中全局覆蓋驗證錯誤響應的樣式。爲此,請使用自定義異常處理程序,如上所述。
默認狀況下,此異常會致使 HTTP 狀態碼 "400 Bad Request" 的響應。