DRF之異常捕獲原始碼分析

ssrheart發表於2024-04-23

DRF之異常捕獲原始碼分析

【一】異常捕獲介紹

  • Django Rest Framework(DRF)是一個用於構建Web API的強大框架,它提供了一種處理異常的機制,使開發人員能夠捕獲和處理各種異常情況。
  • DRF中的異常捕獲類是用於捕獲和處理這些異常的關鍵元件之一。

【二】異常捕獲流程分析

# 全域性異常處理
# 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',
  • 透過上述配置
    • 當發生異常時,系統會呼叫該函式進行異常處理。
  • 在該函式中,可以執行一些自定義的操作來處理異常
    • 比如記錄日誌、返回統一的錯誤響應等。

【三】exception_handler原始碼分析

# exc: 這是引發的異常物件,它是一個Python異常類的例項。
# context: 這是一個字典,包含了有關異常上下文的資訊,通常包括請求物件和檢視物件等。
def exception_handler(exc, context):
    """
    Returns the response that should be used for any given exception.

    By default we handle the REST framework `APIException`, and also
    Django's built-in `Http404` and `PermissionDenied` exceptions.

    Any unhandled exceptions may return `None`, which will cause a 500 error
    to be raised.
    """
    
    # exception_handler 函式首先檢查異常物件 exc 的型別,然後根據異常型別返回適當的HTTP響應
    if isinstance(exc, Http404):
        # 如果異常是 Http404 型別(即頁面不存在),則將其替換為 DRF 中的 NotFound 異常。
        exc = exceptions.NotFound()
        
    elif isinstance(exc, PermissionDenied):
        # 如果異常是 PermissionDenied 型別(即許可權被拒絕),則將其替換為 DRF 中的 PermissionDenied 異常。
        exc = exceptions.PermissionDenied()
	
    # 檢查異常是否屬於 APIException 型別,這是DRF中異常的基類
    # 如果是 APIException 型別
    if isinstance(exc, exceptions.APIException):
        # 它將為異常設定HTTP響應的頭資訊(如認證頭和重試頭)
        headers = {}
        # 如果異常具有 auth_header 屬性,將該屬性的值新增到響應的 WWW-Authenticate 頭資訊中。
        # 這通常用於處理身份驗證相關的異常。
        if getattr(exc, 'auth_header', None):
            # 並將異常的詳細資訊包裝在響應資料中
            headers['WWW-Authenticate'] = exc.auth_header
            
        # 如果異常具有 wait 屬性,將該屬性的值新增到響應的 Retry-After 頭資訊中。
        # 這通常用於指示客戶端應該等待多長時間後再次嘗試請求。
        if getattr(exc, 'wait', None):
            # 並將異常的詳細資訊包裝在響應資料中
            headers['Retry-After'] = '%d' % exc.wait
		
        # 根據異常的 detail 屬性建立響應資料。如果 detail 是列表或字典,則直接使用;否則,將其包裝在一個字典中
        if isinstance(exc.detail, (list, dict)):
            data = exc.detail
        else:
            data = {'detail': exc.detail}
		
        # 呼叫 set_rollback() 來確保資料庫回滾(如果有的話)
        # set_rollback(): 這個函式用於確保資料庫事務回滾,以防異常發生在資料庫事務內部。
        set_rollback()
        
        # 返回一個DRF響應物件
        return Response(data, status=exc.status_code, headers=headers)

    return None

【四】DRF的異常型別原始碼分析

def _get_error_details(data, default_code=None):
    """
    # 將巢狀的資料結構中的潛在翻譯字串或字串轉換為 ErrorDetail 物件。
    Descend into a nested data structure, forcing any
    lazy translation strings or strings into `ErrorDetail`.
    """
    
    # 處理列表或元組型別的資料。
    # 如果資料是列表或元組,它會迭代其中的每個元素
    if isinstance(data, (list, tuple)):
        
        # 遞迴呼叫 _get_error_details 函式來處理每個元素,並將結果儲存在 ret 列表中。
        ret = [
            _get_error_details(item, default_code) for item in data
        ]
        # 如果原始資料是 ReturnList 型別(DRF中的特殊列表型別),則將結果包裝在一個新的 ReturnList 物件中;
        if isinstance(data, ReturnList):
            # 否則,直接返回 ret 列表。
            return ReturnList(ret, serializer=data.serializer)
        return ret
    
    # 如果資料是字典,它會迭代其中的每個鍵值對
    elif isinstance(data, dict):
        
        # 遞迴呼叫 _get_error_details 函式來處理每個值,並將結果儲存在 ret 字典中。
        ret = {
            key: _get_error_details(value, default_code)
            for key, value in data.items()
        }
        # 如果原始資料是 ReturnDict 型別(DRF中的特殊字典型別)
        if isinstance(data, ReturnDict):
            # ,則將結果包裝在一個新的 ReturnDict 物件中
            return ReturnDict(ret, serializer=data.serializer)
        # 否則,直接返回 ret 字典
        return ret
	
    # 如果資料既不是列表/元組也不是字典,那麼它被視為文字資料。
    # 這裡使用 force_str 函式將資料強制轉換為字串,然後檢查是否存在 code 屬性。
    # 如果存在 code 屬性,將其作為錯誤程式碼;
    # 否則,使用 default_code。
    # 然後,建立一個 ErrorDetail 物件,其中包含文字和錯誤程式碼,並將其返回。
    text = force_str(data)
    code = getattr(data, 'code', default_code)
    return ErrorDetail(text, code)

# 獲取異常詳細資訊中的錯誤程式碼,以便在響應中提供錯誤資訊的標識。
def _get_codes(detail):
    # 引數 detail,該引數可以是任何資料型別(通常是巢狀的錯誤詳細資訊)。
    # 函式首先檢查 detail 是否為列表
    # 如果是列表,則遞迴呼叫 _get_codes 函式處理列表中的每個元素。
    if isinstance(detail, list):
        return [_get_codes(item) for item in detail]
    
    # 如果 detail 是字典,則遞迴呼叫 _get_codes 函式處理字典中的每個值。
    elif isinstance(detail, dict):
        return {key: _get_codes(value) for key, value in detail.items()}
    
    # 最終,如果 detail 不是列表或字典,而是具有 code 屬性的物件,就返回該物件的 code 屬性。
    return detail.code

# 獲取異常詳細資訊的完整內容,以便在響應中提供詳細的錯誤資訊和錯誤程式碼。
def _get_full_details(detail):
    # 引數 detail,該引數可以是任何資料型別(通常是巢狀的錯誤詳細資訊)。
    # 函式首先檢查 detail 是否為列表,如果是列表,則遞迴呼叫 _get_full_details 函式處理列表中的每個元素。
    if isinstance(detail, list):
        return [_get_full_details(item) for item in detail]
    elif isinstance(detail, dict):
        # 如果 detail 是字典,則遞迴呼叫 _get_full_details 函式處理字典中的每個值。
        return {key: _get_full_details(value) for key, value in detail.items()}
    # 最終,如果 detail 不是列表或字典,而是具有 code 屬性的物件,就建立一個包含 message 和 code 的字典並返回。
    return {
        'message': detail,
        'code': detail.code
    }

# 用於表示API異常的詳細資訊
class ErrorDetail(str):
    """
    A string-like object that can additionally have a code.
    """
    # 用於儲存錯誤程式碼,預設為 None。
    code = None
	
    # 類的建構函式,它在物件建立時被呼叫。
    # 它接受兩個引數:string 是字串的內容,code 是錯誤程式碼。
    def __new__(cls, string, code=None):
        # 它使用 super().__new__(cls, string) 來建立一個新的字串物件
        self = super().__new__(cls, string)
        # 並將錯誤程式碼賦值給 self.code。最後,它返回新建立的物件。
        self.code = code
        return self

    # 物件的等於(==)運算子的過載方法。
    def __eq__(self, other):
        result = super().__eq__(other)
        # 它用於比較兩個 ErrorDetail 物件是否相等。
        if result is NotImplemented:
            return NotImplemented
        try:
            # 如果兩個物件的內容相等並且它們的錯誤程式碼也相等,返回 True;否則,返回 False。
            return result and self.code == other.code
        except AttributeError:
            return result
	
    # 物件的不等於(!=)運算子的過載方法。
    def __ne__(self, other):
        # 它使用 __eq__ 方法來實現不等於運算子。
        result = self.__eq__(other)
        if result is NotImplemented:
            return NotImplemented
        return not result
	
    # 物件的字串表示方法,用於返回物件的可列印字串表示。
    # 它返回一個格式化的字串,包含了字串內容和錯誤程式碼。
    def __repr__(self):
        return 'ErrorDetail(string=%r, code=%r)' % (
            str(self),
            self.code,
        )
	# 物件的雜湊方法,用於生成物件的雜湊值。
    # 它基於字串內容的雜湊值生成物件的雜湊值。
    def __hash__(self):
        return hash(str(self))

# 這個類是所有DRF異常的基類,其他自定義異常應該從這個類繼承,並提供特定的 status_code 和 default_detail 屬性
class APIException(Exception):
    """
    Base class for REST framework exceptions.
    Subclasses should provide `.status_code` and `.default_detail` properties.
    """
    # 這個屬性指定了預設的HTTP狀態程式碼,如果子類沒有提供自定義的 status_code,則預設為500(內部伺服器錯誤)。
    status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
    # 這個屬性指定了預設的異常詳細資訊,它是一個本地化字串,用於描述異常的內容。
    # 在這裡,使用了 _() 函式來標記該字串以進行國際化/本地化處理。
    default_detail = _('A server error occurred.')
    # 這個屬性指定了預設的錯誤程式碼,用於標識異常型別。預設為 'error'。
    default_code = 'error'
	
    # 類的建構函式,它接受兩個可選引數:detail 和 code
    def __init__(self, detail=None, code=None):
        # 建構函式首先檢查這兩個引數是否為 None
        # 如果是,就將它們設定為預設值(default_detail 和 default_code)。
        if detail is None:
            detail = self.default_detail
        if code is None:
            code = self.default_code
            
        # 然後,建構函式呼叫 _get_error_details 函式來處理 detail 和 code,並將結果儲存在 self.detail 屬性中。
        self.detail = _get_error_details(detail, code)

    def __str__(self):
        # 返回異常的字串表示,通常是異常詳細資訊的字串表示。
        return str(self.detail)
	
    # 獲取異常詳細資訊中的錯誤程式碼。
    def get_codes(self):
        """
        Return only the code part of the error details.

        Eg. {"name": ["required"]}
        """
        # 它呼叫 _get_codes 函式來處理 self.detail,並返回結果。
        return _get_codes(self.detail)
	
    # 獲取異常詳細資訊的完整內容,包括訊息和錯誤程式碼。
    def get_full_details(self):
        """
        Return both the message & code parts of the error details.

        Eg. {"name": [{"message": "This field is required.", "code": "required"}]}
        """
        # 它呼叫 _get_full_details 函式來處理 self.detail,並返回結果。
        return _get_full_details(self.detail)
    
    
# 用於表示API請求中的驗證錯誤,通常與HTTP 400 Bad Request狀態一起使用。
class ValidationError(APIException):
    # 這個屬性指定了 HTTP 400 Bad Request 狀態程式碼,表示請求的內容或引數不符合要求。
    status_code = status.HTTP_400_BAD_REQUEST
    # 這個屬性指定了預設的異常詳細資訊,用於描述驗證失敗的原因。它是一個本地化字串,通常為 "Invalid input."。
    default_detail = _('Invalid input.')
    # 這個屬性指定了預設的錯誤程式碼,用於標識驗證失敗。預設為 'invalid'。
    default_code = 'invalid'
	
    # 類的建構函式,它接受兩個可選引數:detail 和 code。
    def __init__(self, detail=None, code=None):
        # 檢查這兩個引數是否為 None
        # 如果是,就將它們設定為預設值(default_detail 和 default_code)。
        if detail is None:
            detail = self.default_detail
        if code is None:
            code = self.default_code

        # For validation failures, we may collect many errors together,
        # so the details should always be coerced to a list if not already.
        # 然後,建構函式檢查 detail 是否為元組
        # 如果是,將其轉換為列表;
        if isinstance(detail, tuple):
            detail = list(detail)
            
        # 如果 detail 既不是字典也不是列表,將其包裝成一個列表。
        elif not isinstance(detail, dict) and not isinstance(detail, list):
            detail = [detail]
	
    	# 最後,建構函式呼叫 _get_error_details 函式來處理 detail 和 code,並將結果儲存在 self.detail 屬性中。
        self.detail = _get_error_details(detail, code)

#  表示解析請求時出現錯誤,通常對應HTTP 400 Bad Request狀態。
# 預設詳細資訊為 "Malformed request."。
class ParseError(APIException):
    status_code = status.HTTP_400_BAD_REQUEST
    default_detail = _('Malformed request.')
    default_code = 'parse_error'

#  表示身份驗證失敗,通常對應HTTP 401 Unauthorized狀態。
# 預設詳細資訊為 "Incorrect authentication credentials."。
class AuthenticationFailed(APIException):
    status_code = status.HTTP_401_UNAUTHORIZED
    default_detail = _('Incorrect authentication credentials.')
    default_code = 'authentication_failed'

# 表示未提供身份驗證憑據,通常對應HTTP 401 Unauthorized狀態。
# 預設詳細資訊為 "Authentication credentials were not provided."。
class NotAuthenticated(APIException):
    status_code = status.HTTP_401_UNAUTHORIZED
    default_detail = _('Authentication credentials were not provided.')
    default_code = 'not_authenticated'

#  表示沒有執行此操作的許可權,通常對應HTTP 403 Forbidden狀態。
# 預設詳細資訊為 "You do not have permission to perform this action."。
class PermissionDenied(APIException):
    status_code = status.HTTP_403_FORBIDDEN
    default_detail = _('You do not have permission to perform this action.')
    default_code = 'permission_denied'

# 表示資源未找到,通常對應HTTP 404 Not Found狀態。
# 預設詳細資訊為 "Not found."。
class NotFound(APIException):
    status_code = status.HTTP_404_NOT_FOUND
    default_detail = _('Not found.')
    default_code = 'not_found'

# 表示請求的HTTP方法不允許,通常對應HTTP 405 Method Not Allowed狀態。它包括一個額外的引數 method,用於指定不允許的HTTP方法。
# 預設詳細資訊為 "Method "{method}" not allowed."。
class MethodNotAllowed(APIException):
    status_code = status.HTTP_405_METHOD_NOT_ALLOWED
    default_detail = _('Method "{method}" not allowed.')
    default_code = 'method_not_allowed'

    def __init__(self, method, detail=None, code=None):
        if detail is None:
            detail = force_str(self.default_detail).format(method=method)
        super().__init__(detail, code)

# 表示無法滿足請求的Accept頭部,通常對應HTTP 406 Not Acceptable狀態。
# 它包括一個額外的引數 available_renderers,用於指定可用的渲染器。
# 預設詳細資訊為 "Could not satisfy the request Accept header."。
class NotAcceptable(APIException):
    status_code = status.HTTP_406_NOT_ACCEPTABLE
    default_detail = _('Could not satisfy the request Accept header.')
    default_code = 'not_acceptable'

    def __init__(self, detail=None, code=None, available_renderers=None):
        self.available_renderers = available_renderers
        super().__init__(detail, code)

# 表示請求中包含了不支援的媒體型別(Media Type),通常對應HTTP 415 Unsupported Media Type狀態。
# 它包括一個額外的引數 media_type,用於指定不支援的媒體型別。
# 預設詳細資訊為 "Unsupported media type "{media_type}" in request."。
class UnsupportedMediaType(APIException):
    status_code = status.HTTP_415_UNSUPPORTED_MEDIA_TYPE
    default_detail = _('Unsupported media type "{media_type}" in request.')
    default_code = 'unsupported_media_type'

    def __init__(self, media_type, detail=None, code=None):
        if detail is None:
            detail = force_str(self.default_detail).format(media_type=media_type)
        super().__init__(detail, code)

# 表示請求被限速(Throttled),通常對應HTTP 429 Too Many Requests狀態。
# 它包括一個額外的引數 wait,用於指定還需等待多少時間才能再次進行請求。
# 預設詳細資訊為 "Request was throttled.",並且根據 wait 引數動態生成額外的詳細資訊,用於描述還需等待的時間。
class Throttled(APIException):
    status_code = status.HTTP_429_TOO_MANY_REQUESTS
    default_detail = _('Request was throttled.')
    extra_detail_singular = _('Expected available in {wait} second.')
    extra_detail_plural = _('Expected available in {wait} seconds.')
    default_code = 'throttled'

    def __init__(self, wait=None, detail=None, code=None):
        if detail is None:
            detail = force_str(self.default_detail)
        if wait is not None:
            wait = math.ceil(wait)
            detail = ' '.join((
                detail,
                force_str(ngettext(self.extra_detail_singular.format(wait=wait),
                                   self.extra_detail_plural.format(wait=wait),
                                   wait))))
        self.wait = wait
        super().__init__(detail, code)

#  這個函式是用於處理通用的伺服器錯誤,通常對應HTTP 500 Internal Server Error狀態。
# 當伺服器發生未處理的異常時,Django會呼叫這個檢視函式。該函式返回一個JSON響應,其中包含一個簡單的錯誤訊息,狀態程式碼為HTTP 500。
def server_error(request, *args, **kwargs):
    """
    Generic 500 error handler.
    """
    data = {
        'error': 'Server Error (500)'
    }
    return JsonResponse(data, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

# 這個函式是用於處理通用的客戶端請求錯誤,通常對應HTTP 400 Bad Request狀態。
# 當Django無法處理客戶端請求時(例如,請求的資料格式不正確),或者檢視中丟擲了 ValidationError 異常時,Django會呼叫這個檢視函式。
# 該函式返回一個JSON響應,其中包含一個簡單的錯誤訊息,狀態程式碼為HTTP 400。
def bad_request(request, exception, *args, **kwargs):
    """
    Generic 400 error handler.
    """
    data = {
        'error': 'Bad Request (400)'
    }
    return JsonResponse(data, status=status.HTTP_400_BAD_REQUEST)

【五】自定義異常捕獲類

from rest_framework.views import exception_handler
from rest_framework.response import Response

from .common_logger import logger


# 日誌記錄必要的報錯資訊
# 記錄日誌資訊必含:使用者地址 + 使用者ID + 請求地址 + 執行的檢視函式 + 異常原因

def common_exception_handler(exc, context):
    # 獲取請求物件
    request = context.get('request')

    # 獲取檢視物件
    view = context.get('view')

    # 獲取請求的IP地址
    ip = request.META.get('REMOTE_ADDR')

    try:
        # 嘗試獲取使用者ID,如果使用者未登入,則設定為"未登入使用者"
        user_id = request.user.id
    except:
        user_id = "未登入使用者"

    # 獲取請求的完整路徑
    path = request.get_full_path()

    # 將檢視物件轉換為字串以記錄日誌
    view_str = str(view)

    # 呼叫預設異常處理函式獲取異常響應
    res = exception_handler(exc, context)

    # 構建錯誤日誌資訊
    error = f'當前使用者地址 : {ip} , 使用者ID : {user_id} , 請求地址 : {path} , 執行的檢視函式 {view_str} , 異常原因 : {str(exc)}'

    # 使用日誌記錄器記錄錯誤日誌
    logger.error(error)

    if res:
        # 如果存在異常響應

        if isinstance(res.data, dict):
            # 如果異常響應的資料是字典型別,一般是DRF的異常
            # DRF 異常:一種是從 res.data 中取/一種是從 data 中取
            data = {"code": 999, "msg": res.data.get("detail", "系統錯誤,請聯絡管理員")}
        else:
            # 如果異常響應的資料不是字典型別,通常是其他異常
            data = {"code": 888, "msg": str(exc)}
            
        # 返回自定義的異常響應
        return Response(data)

【六】DRF自帶的響應狀態碼

from rest_framework import status 
# 判斷給定的HTTP狀態碼是否屬於資訊性狀態碼,資訊性狀態碼的範圍是100到199。
def is_informational(code):
    return 100 <= code <= 199

# 判斷給定的HTTP狀態碼是否屬於成功狀態碼,成功狀態碼的範圍是200到299。
def is_success(code):
    return 200 <= code <= 299

# 判斷給定的HTTP狀態碼是否屬於重定向狀態碼,重定向狀態碼的範圍是300到399。
def is_redirect(code):
    return 300 <= code <= 399

# 判斷給定的HTTP狀態碼是否屬於客戶端錯誤狀態碼,客戶端錯誤狀態碼的範圍是400到499。
def is_client_error(code):
    return 400 <= code <= 499

# 判斷給定的HTTP狀態碼是否屬於伺服器錯誤狀態碼,伺服器錯誤狀態碼的範圍是500到599。
def is_server_error(code):
    return 500 <= code <= 599


# 1xx(資訊性狀態碼)表示請求已被接受,繼續處理。
# 繼續。伺服器僅接受客戶端請求的一部分,等待客戶端繼續傳送請求。
HTTP_100_CONTINUE = 100  
# 切換協議。伺服器將遵從客戶的請求切換協議。
HTTP_101_SWITCHING_PROTOCOLS = 101  
# 處理中。伺服器正在處理請求,但需要更多時間。
HTTP_102_PROCESSING = 102  
# 提前提示。伺服器可以將頭資訊返回給客戶端,以提前表示響應可能的形式。
HTTP_103_EARLY_HINTS = 103  


# 2xx(成功狀態碼)表示請求已成功接收、理解、接受。
# OK。請求已成功,請求所希望的響應頭或資料體將隨此響應返回。
HTTP_200_OK = 200  
# 已建立。請求已經被實現,而且有一個新的資源已經依據請求的需要而建立。
HTTP_201_CREATED = 201  
# 已接受。伺服器已接受請求,但尚未處理。
HTTP_202_ACCEPTED = 202  
# 非授權資訊。伺服器已成功處理了請求,但返回的資訊可能來自另一來源。
HTTP_203_NON_AUTHORITATIVE_INFORMATION = 203 
# 無內容。伺服器成功處理了請求,但沒有返回任何內容。
HTTP_204_NO_CONTENT = 204  
# 重置內容。伺服器成功處理了請求,使用者代理必須重置文件檢視。
HTTP_205_RESET_CONTENT = 205  
# 部分內容。伺服器已經成功處理了部分 GET 請求。
HTTP_206_PARTIAL_CONTENT = 206  
# 多狀態。XML 資料包含可執行的多個狀態。
HTTP_207_MULTI_STATUS = 207  
# 已報告。資源已在之前的請求中報告,返回的響應應該是被引用資源的當前狀態。
HTTP_208_ALREADY_REPORTED = 208 
# IM Used。伺服器已經滿足了對資源的請求,響應是對實體(如 HTML 頁面或 JSON 檔案)的表示。
HTTP_226_IM_USED = 226  


# 3xx(重定向狀態碼)表示客戶必須採取進一步的操作才能完成請求。
# 多種選擇。被請求的資源存在多種可供選擇的響應。
HTTP_300_MULTIPLE_CHOICES = 300  
# 永久移動。請求的資源已被永久移動到新 URI。
HTTP_301_MOVED_PERMANENTLY = 301  
# 找到。請求的資源現在臨時從不同的 URI 響應請求。
HTTP_302_FOUND = 302  
# 參見其他。對應當前請求的響應可以在另一個 URI 上被找到。
HTTP_303_SEE_OTHER = 303  
# 未修改。自從上次請求後,請求的資源未被修改過。
HTTP_304_NOT_MODIFIED = 304 
# 使用代理。請求的資源必須透過指定的代理才能被訪問。
HTTP_305_USE_PROXY = 305  
# 保留。該狀態碼將被任何操作繼續執行之前,需要客戶端的進一步操作來完成請求。
HTTP_306_RESERVED = 306  
# 臨時重定向。請求的資源現在臨時從不同的 URI 響應請求。
HTTP_307_TEMPORARY_REDIRECT = 307  
# 永久重定向。請求的資源已被永久移動到新 URI。
HTTP_308_PERMANENT_REDIRECT = 308  


# 4xx(客戶端錯誤狀態碼)表示客戶端看起來可能發生了錯誤。
# 錯誤請求。伺服器不理解請求的語法。
HTTP_400_BAD_REQUEST = 400  
# 未授權。請求要求身份驗證。
HTTP_401_UNAUTHORIZED = 401  
# 需要付款。保留供將來使用。
HTTP_402_PAYMENT_REQUIRED = 402  
# 禁止。伺服器拒絕請求。
HTTP_403_FORBIDDEN = 403  
# 未找到。伺服器找不到請求的資源。
HTTP_404_NOT_FOUND = 404  
# 方法不允許。請求中指定的方法不被允許。
HTTP_405_METHOD_NOT_ALLOWED = 405  
# 不可接受。伺服器只生成不可接受的響應。
HTTP_406_NOT_ACCEPTABLE = 406  
# 需要代理身份驗證。客戶端必須先使用代理認證。
HTTP_407_PROXY_AUTHENTICATION_REQUIRED = 407  
# 請求超時。伺服器等候請求時發生超時。
HTTP_408_REQUEST_TIMEOUT = 408  
# 衝突。請求在當前資源狀態下無法執行。
HTTP_409_CONFLICT = 409  
# 消失。請求的資源已被永久刪除。
HTTP_410_GONE = 410  
# 需要長度。伺服器拒絕在沒有定義 Content-Length 頭的情況下接受請求。
HTTP_411_LENGTH_REQUIRED = 411 
# 前提條件不滿足。請求中給定的前提條件由伺服器評估為 false。
HTTP_412_PRECONDITION_FAILED = 412  
# 請求實體過大。伺服器拒絕處理請求,因為請求實體過大。
HTTP_413_REQUEST_ENTITY_TOO_LARGE = 413  
# 請求 URI 過長。伺服器拒絕提供服務,因為請求的 URI 過長。
HTTP_414_REQUEST_URI_TOO_LONG = 414  
# 不支援的媒體型別。伺服器拒絕處理不支援的媒體型別的請求。
HTTP_415_UNSUPPORTED_MEDIA_TYPE = 415  
# 請求範圍不符合要求。頁面無法提供請求的範圍。
HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE = 416  
# 期望失敗。伺服器未滿足"期望"請求標頭欄位的要求。
HTTP_417_EXPECTATION_FAILED = 417  
# 我是茶壺。伺服器拒絕嘗試用它不會被燒水的茶壺做咖啡。
HTTP_418_IM_A_TEAPOT = 418 
# 誤導的請求。請求指向了伺服器上不存在的資源。
HTTP_421_MISDIRECTED_REQUEST = 421  
# 不可處理的實體。請求格式正確,但由於語義錯誤而無法滿足。
HTTP_422_UNPROCESSABLE_ENTITY = 422  
# 已鎖定。當前資源被鎖定。
HTTP_423_LOCKED = 423  
# 依賴失敗。由於之前的請求失敗,所以此次請求失敗。
HTTP_424_FAILED_DEPENDENCY = 424  
# 過早。伺服器不願意冒著風險去處理可能重播的請求。
HTTP_425_TOO_EARLY = 425  
# 需要升級。客戶端應切換到TLS/1.0。
HTTP_426_UPGRADE_REQUIRED = 426  
# 先決條件要求。要求先決條件,而請求未滿足。
HTTP_428_PRECONDITION_REQUIRED = 428  
# 請求過多。使用者在給定的時間內傳送了太多請求。
HTTP_429_TOO_MANY_REQUESTS = 429  
# 請求頭欄位太大。伺服器不願意處理請求,因為請求頭欄位太大。
HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE = 431  
# 因法律原因不可用。訪問資源受到法律限制。
HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS = 451 


# 5xx(伺服器錯誤狀態碼)表示伺服器在嘗試處理請求時發生錯誤。
# 內部伺服器錯誤。伺服器遇到錯誤,無法完成請求。
HTTP_500_INTERNAL_SERVER_ERROR = 500  
# 未實現。伺服器不具備完成請求的功能。
HTTP_501_NOT_IMPLEMENTED = 501  
# 錯誤閘道器。伺服器作為閘道器或代理,從上游伺服器收到了無效的響應。
HTTP_502_BAD_GATEWAY = 502  
# 服務不可用。伺服器目前無法提供請求所需的服務。
HTTP_503_SERVICE_UNAVAILABLE = 503  
# 閘道器超時。伺服器作為閘道器或代理,未及時從上游伺服器接收請求。
HTTP_504_GATEWAY_TIMEOUT = 504  
# HTTP 版本不受支援。伺服器不支援請求中所用的 HTTP 協議版本。
HTTP_505_HTTP_VERSION_NOT_SUPPORTED = 505  
# 內容協商。伺服器存在內部配置問題。
HTTP_506_VARIANT_ALSO_NEGOTIATES = 506  
# 儲存不足。伺服器無法儲存完成請求所必須的內容。
HTTP_507_INSUFFICIENT_STORAGE = 507  
# 檢測到迴圈。伺服器檢測到無限迴圈。
HTTP_508_LOOP_DETECTED = 508  
# 超出頻寬限制。伺服器達到頻寬限制。
HTTP_509_BANDWIDTH_LIMIT_EXCEEDED = 509  
# 擴充套件未執行。客戶端需要進一步執行操作以完成請求。
HTTP_510_NOT_EXTENDED = 510  
# 需要網路認證。客戶端需要進行網路身份驗證才能獲得請求的響應。
HTTP_511_NETWORK_AUTHENTICATION_REQUIRED = 511  

相關文章