http内置库文档:https://docs.python.org/zh-cn/3.10/library/http.html
http 是一个包,它收集了多个用于处理超文本传输协议的模块:
- http.client 是一个底层的 HTTP 协议客户端;对于高层级的 URL 访问请使用 urllib.request
- http.server 包含基于 socketserver 的基本 HTTP 服务类
- http.cookies 包含一些有用来实现通过cookies 进行状态管理的工具
- http.cookiejar 提供了 cookies 的持久化
http 也是一个通过 http.HTTPStatus 枚举定义了一些 HTTP 状态码以及相关联消息的模块
1、源码
from enum import IntEnum
__all__ = ['HTTPStatus']
class HTTPStatus(IntEnum):
def __new__(cls, value, phrase, description=''):
obj = int.__new__(cls, value)
obj._value_ = value
obj.phrase = phrase
obj.description = description
return obj
# informational
CONTINUE = 100, 'Continue', 'Request received, please continue'
SWITCHING_PROTOCOLS = (101, 'Switching Protocols',
'Switching to new protocol; obey Upgrade header')
PROCESSING = 102, 'Processing'
EARLY_HINTS = 103, 'Early Hints'
# success
OK = 200, 'OK', 'Request fulfilled, document follows'
CREATED = 201, 'Created', 'Document created, URL follows'
ACCEPTED = (202, 'Accepted',
'Request accepted, processing continues off-line')
NON_AUTHORITATIVE_INFORMATION = (203,
'Non-Authoritative Information', 'Request fulfilled from cache')
NO_CONTENT = 204, 'No Content', 'Request fulfilled, nothing follows'
RESET_CONTENT = 205, 'Reset Content', 'Clear input form for further input'
PARTIAL_CONTENT = 206, 'Partial Content', 'Partial content follows'
MULTI_STATUS = 207, 'Multi-Status'
ALREADY_REPORTED = 208, 'Already Reported'
IM_USED = 226, 'IM Used'
# redirection
MULTIPLE_CHOICES = (300, 'Multiple Choices',
'Object has several resources -- see URI list')
MOVED_PERMANENTLY = (301, 'Moved Permanently',
'Object moved permanently -- see URI list')
FOUND = 302, 'Found', 'Object moved temporarily -- see URI list'
SEE_OTHER = 303, 'See Other', 'Object moved -- see Method and URL list'
NOT_MODIFIED = (304, 'Not Modified',
'Document has not changed since given time')
USE_PROXY = (305, 'Use Proxy',
'You must use proxy specified in Location to access this resource')
TEMPORARY_REDIRECT = (307, 'Temporary Redirect',
'Object moved temporarily -- see URI list')
PERMANENT_REDIRECT = (308, 'Permanent Redirect',
'Object moved permanently -- see URI list')
# client error
BAD_REQUEST = (400, 'Bad Request',
'Bad request syntax or unsupported method')
UNAUTHORIZED = (401, 'Unauthorized',
'No permission -- see authorization schemes')
PAYMENT_REQUIRED = (402, 'Payment Required',
'No payment -- see charging schemes')
FORBIDDEN = (403, 'Forbidden',
'Request forbidden -- authorization will not help')
NOT_FOUND = (404, 'Not Found',
'Nothing matches the given URI')
METHOD_NOT_ALLOWED = (405, 'Method Not Allowed',
'Specified method is invalid for this resource')
NOT_ACCEPTABLE = (406, 'Not Acceptable',
'URI not available in preferred format')
PROXY_AUTHENTICATION_REQUIRED = (407,
'Proxy Authentication Required',
'You must authenticate with this proxy before proceeding')
REQUEST_TIMEOUT = (408, 'Request Timeout',
'Request timed out; try again later')
CONFLICT = 409, 'Conflict', 'Request conflict'
GONE = (410, 'Gone',
'URI no longer exists and has been permanently removed')
LENGTH_REQUIRED = (411, 'Length Required',
'Client must specify Content-Length')
PRECONDITION_FAILED = (412, 'Precondition Failed',
'Precondition in headers is false')
REQUEST_ENTITY_TOO_LARGE = (413, 'Request Entity Too Large',
'Entity is too large')
REQUEST_URI_TOO_LONG = (414, 'Request-URI Too Long',
'URI is too long')
UNSUPPORTED_MEDIA_TYPE = (415, 'Unsupported Media Type',
'Entity body in unsupported format')
REQUESTED_RANGE_NOT_SATISFIABLE = (416,
'Requested Range Not Satisfiable',
'Cannot satisfy request range')
EXPECTATION_FAILED = (417, 'Expectation Failed',
'Expect condition could not be satisfied')
IM_A_TEAPOT = (418, 'I\'m a Teapot',
'Server refuses to brew coffee because it is a teapot.')
MISDIRECTED_REQUEST = (421, 'Misdirected Request',
'Server is not able to produce a response')
UNPROCESSABLE_ENTITY = 422, 'Unprocessable Entity'
LOCKED = 423, 'Locked'
FAILED_DEPENDENCY = 424, 'Failed Dependency'
TOO_EARLY = 425, 'Too Early'
UPGRADE_REQUIRED = 426, 'Upgrade Required'
PRECONDITION_REQUIRED = (428, 'Precondition Required',
'The origin server requires the request to be conditional')
TOO_MANY_REQUESTS = (429, 'Too Many Requests',
'The user has sent too many requests in '
'a given amount of time ("rate limiting")')
REQUEST_HEADER_FIELDS_TOO_LARGE = (431,
'Request Header Fields Too Large',
'The server is unwilling to process the request because its header '
'fields are too large')
UNAVAILABLE_FOR_LEGAL_REASONS = (451,
'Unavailable For Legal Reasons',
'The server is denying access to the '
'resource as a consequence of a legal demand')
# server errors
INTERNAL_SERVER_ERROR = (500, 'Internal Server Error',
'Server got itself in trouble')
NOT_IMPLEMENTED = (501, 'Not Implemented',
'Server does not support this operation')
BAD_GATEWAY = (502, 'Bad Gateway',
'Invalid responses from another server/proxy')
SERVICE_UNAVAILABLE = (503, 'Service Unavailable',
'The server cannot process the request due to a high load')
GATEWAY_TIMEOUT = (504, 'Gateway Timeout',
'The gateway server did not receive a timely response')
HTTP_VERSION_NOT_SUPPORTED = (505, 'HTTP Version Not Supported',
'Cannot fulfill request')
VARIANT_ALSO_NEGOTIATES = 506, 'Variant Also Negotiates'
INSUFFICIENT_STORAGE = 507, 'Insufficient Storage'
LOOP_DETECTED = 508, 'Loop Detected'
NOT_EXTENDED = 510, 'Not Extended'
NETWORK_AUTHENTICATION_REQUIRED = (511,
'Network Authentication Required',
'The client needs to authenticate to gain network access')
定义了一个名为 HTTPStatus 的 Python 类,该类继承自 IntEnum,这是 Python 内置 enum 模块中的一个子类,用于创建具有整数值的枚举类型。这个特定的 HTTPStatus 类是为了表示 HTTP 协议中的所有状态码及其相关的描述(原因短语)和详细说明。
通过这种方式组织,开发人员可以轻松地在他们的 HTTP 相关代码中使用这些枚举值,增加代码的可读性和安全性,因为这样可以防止由于手动输入状态码数字导致的错误,并且 IDE 和静态分析工具也能更好地识别和提示这些状态码。
2、示例
from your_module import HTTPStatus
# 创建一个 HTTPStatus 的实例
status = HTTPStatus.OK
# 访问状态码数值
print(status.value) # 输出:200
# 访问原因短语
print(status.phrase) # 输出:"OK"
# 访问详细描述
print(status.description) # 输出:"Request fulfilled, document follows"
# 也可以通过名字获取状态码
status = HTTPStatus.NOT_FOUND
# 输出状态码及其相关信息
print(status.name, status.value, status.phrase, status.description)
# 输出:"NOT_FOUND 404 Not Found Nothing matches the given URI"
3、核心代码解析
def __new__(cls, value, phrase, description=''):
obj = int.__new__(cls, value)
obj._value_ = value
obj.phrase = phrase
obj.description = description
return obj
在这段代码中,__new__
是 Python 中的一个特殊方法,它是类实例化过程中的一个重要步骤。在这里,__new__
方法被重写以定制 HTTPStatus
类实例的创建过程。
__new__
方法接收四个参数:cls
(当前类)、value
(HTTP 状态码的整数值)、phrase
(对应状态码的原因短语)和 description
(状态码的详细描述,默认为空字符串)。
-
int.__new__(cls, value)
:调用int
类的__new__
方法来创建一个新的实例,但是返回的对象类型是HTTPStatus
类而非int
类。这意味着我们创建的是一个整数类型的HTTPStatus
子类实例。 -
obj._value_ = value
:设置_value_
属性,这是 Enum 类要求的特殊属性,用于存储枚举成员的实际值。在这里就是给每个 HTTP 状态码分配其对应的数值。 -
obj.phrase = phrase
和obj.description = description
:分别给新创建的枚举成员对象添加两个自定义属性,即phrase
和description
,分别存储状态码的原因短语和详细描述。 -
return obj
:最后返回创建好的带有附加属性的HTTPStatus
实例。
通过这样的设计,每次创建 HTTPStatus
类的一个状态码实例时,都会同时携带状态码数值、原因短语和描述信息,增强了对 HTTP 状态码的表达能力,使其更具可读性和实用性。
3.1、__all__ = [‘HTTPStatus’] 含义?
在Python中,__all__ 是一个特殊变量,它用于控制模块内哪些名称会被 import * 语句所导入。当你在一个模块中定义了 __all__ 列表,这个列表中的条目包含了你希望对外部世界暴露的所有公共API元素,如函数、类或变量。
3.2、int.new(cls, value) 换成 int(value) 不行吗?
在HTTPStatus
这个例子中,继承自IntEnum
的类使用__new__
方法来创建具有特殊属性(例如phrase
和description
)的枚举成员。这里的目的是确保创建的每个枚举成员都是一个整数,同时带有额外的信息。
当写成 obj = int.__new__(cls, value)
时,它是在调用父类int
的__new__
方法来创建一个实际的整数实例,并将其与当前类(即HTTPStatus
)关联起来。这是正确的方式来构造一个同时作为整数并具有枚举特性的对象。
如果简单地替换为 obj = int(value)
,那么这将仅仅创建一个普通的int
对象,而不是HTTPStatus
类的一个实例。这样做的结果是丢失了枚举所特有的功能,比如可以通过名称访问成员以及保持附加属性的能力。
因此,在定义HTTPStatus
这样的枚举类时,必须按照其__new__
方法所示的方式调用基类int
的__new__
方法,这样才能确保生成的对象既是int
类型,又是HTTPStatus
枚举类的实例。
3.3、为什么是obj.value = value 而不是obj.value = value
在Python的enum
模块中,枚举成员有一个特殊属性_value_
,它是用来存储枚举成员的实际值。将value
赋给obj._value_
的原因在于,enum.Enum
会在内部处理 _value_
属性来正确初始化枚举成员。
当你通过__new__
方法创建一个枚举成员时,_value_
属性被用来标识该枚举成员的具体数值,而不仅仅是任何其他自定义属性。在枚举中,_value_
是用于区分不同枚举成员的关键属性,且在比较枚举成员时会直接参考这个值。
如果简单地设置obj.value = value
,虽然可以给枚举成员添加一个名为value
的属性,但它不会被enum
模块识别为枚举成员的实际值。为了确保枚举的行为符合预期,必须使用_value_
这一特殊属性来存储基础值。