Django REST framework API 指南(24):異常

官方原文連接
本系列文章 github 地址
轉載請註明出處python

異常

REST framework 視圖中的異常處理

REST framework 的視圖處理各類異常,並返回適當的錯誤響應。git

須要處理的異常狀況有:github

  • 在 REST framework 內引起的 APIException的子類。
  • Django 的 Http404 異常。
  • Django 的 PermissionDenied 異常。

在每種狀況下,REST framework 都會返回一個帶有適當狀態碼和內容類型的響應。響應的主體將包含有關錯誤性質的其餘細節。django

大多數錯誤響應將包含響應正文中的關鍵 detailjson

例如,如下請求: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 響應。


API 參考

APIException

簽名: APIException()

APIView 類或 @api_view 中引起的全部異常的基類。

要自定義異常,請繼承 APIException,並在該類上設置 .status_code.default_detaildefault_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 異常

有許多不一樣的屬性可用於檢查 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

簽名: 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 header 時引起。

默認狀況下,此異常會致使 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 類應該用於序列化類和字段驗證以及驗證器類。使用 raise_exception 關鍵字參數調用 serializer.is_valid 時也會引起此問題:

serializer.is_valid(raise_exception=True)
複製代碼

通用視圖使用 raise_exception=True 標誌,意味着你能夠在 API 中全局覆蓋驗證錯誤響應的樣式。爲此,請使用自定義異常處理程序,如上所述。

默認狀況下,此異常會致使 HTTP 狀態碼 "400 Bad Request" 的響應。

相關文章
相關標籤/搜索