DRF之异常捕获源码分析

发布时间 2023-09-19 17:34:46作者: Chimengmeng

【一】异常捕获介绍

  • 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