http.client --- HTTP 协议客户端

源代码: Lib/http/client.py


此模块定义了实现 HTTP 和 HTTPS 协议客户端的类。通常不直接使用它 —— 模块 urllib.request 使用它来处理使用 HTTP 和 HTTPS 的 URL。

参见

对于更高级别的 HTTP 客户端接口,推荐使用 Requests 包

备注

仅当 Python 编译时带有 SSL 支持(通过 ssl 模块)时,HTTPS 支持才可用。

可用性:非 WASI。

此模块在 WebAssembly 上不起作用或不可用。有关更多信息,请参阅 WebAssembly 平台

此模块提供了以下类:

class http.client.HTTPConnection(host, port=None, [timeout, ]source_address=None, blocksize=8192)

一个 HTTPConnection 实例表示与一个 HTTP 服务器的一次事务。它应该通过传递主机和可选的端口号来实例化。如果没有传递端口号,则从主机字符串中提取端口(如果其形式为 host:port),否则使用默认的 HTTP 端口 (80)。如果给定了可选的 timeout 参数,阻塞操作(如连接尝试)将在指定的秒数后超时(如果没有给定,则使用全局默认超时设置)。可选的 source_address 参数可以是一个 (host, port) 元组,用作发起 HTTP 连接的源地址。可选的 blocksize 参数设置了发送类文件消息体的缓冲区大小(以字节为单位)。

例如,以下调用都会创建连接到同一主机和端口的实例:

>>> h1 = http.client.HTTPConnection('www.python.org')
>>> h2 = http.client.HTTPConnection('www.python.org:80')
>>> h3 = http.client.HTTPConnection('www.python.org', 80)
>>> h4 = http.client.HTTPConnection('www.python.org', 80, timeout=10)

在 3.2 版本发生变更: 添加了 source_address

在 3.4 版本发生变更: strict 参数已被移除。不再支持 HTTP 0.9 风格的“简单响应”。

在 3.7 版本发生变更: 添加了 blocksize 参数。

class http.client.HTTPSConnection(host, port=None, *, [timeout, ]source_address=None, context=None, blocksize=8192)

HTTPConnection 的一个子类,使用 SSL 与安全服务器进行通信。默认端口是 443。如果指定了 context,它必须是一个 ssl.SSLContext 实例,用于描述各种 SSL 选项。

请阅读 安全考量 以获取有关最佳实践的更多信息。

在 3.2 版本发生变更: 添加了 source_addresscontextcheck_hostname

在 3.2 版本发生变更: 此类现在在可能的情况下支持 HTTPS 虚拟主机(即,如果 ssl.HAS_SNI 为真)。

在 3.4 版本发生变更: strict 参数已被移除。不再支持 HTTP 0.9 风格的“简单响应”。

在 3.4.3 版本发生变更: 此类现在默认执行所有必要的证书和主机名检查。要恢复到以前未验证的行为,可以将 ssl._create_unverified_context() 传递给 context 参数。

在 3.8 版本发生变更: 对于默认的 context,或者当使用自定义 context 传递 cert_file 时,此类现在会为 ssl.SSLContext.post_handshake_auth 启用 TLS 1.3。

在 3.10 版本发生变更: 当没有提供 context 时,此类现在会发送一个带有协议指示符 http/1.1 的 ALPN 扩展。自定义的 context 应使用 set_alpn_protocols() 来设置 ALPN 协议。

在 3.12 版本发生变更: 已移除已弃用的 key_filecert_filecheck_hostname 参数。

class http.client.HTTPResponse(sock, debuglevel=0, method=None, url=None)

连接成功后返回其实例的类。不由用户直接实例化。

在 3.4 版本发生变更: strict 参数已被移除。不再支持 HTTP 0.9 风格的“简单响应”。

此模块提供了以下函数:

http.client.parse_headers(fp)

从一个代表 HTTP 请求/响应的文件指针 fp 中解析标头。该文件必须是一个 BufferedIOBase 读取器(即非文本),并且必须提供一个有效的 RFC 2822 风格的标头。

此函数返回一个 http.client.HTTPMessage 的实例,该实例包含标头字段,但没有有效负载(与 HTTPResponse.msghttp.server.BaseHTTPRequestHandler.headers 相同)。返回后,文件指针 fp 已准备好读取 HTTP 主体。

备注

parse_headers() 不解析 HTTP 消息的起始行;它只解析 Name: value 格式的行。文件必须已准备好读取这些字段行,因此在调用该函数之前,第一行应已被消费。

以下异常会在适当的时候被引发:

exception http.client.HTTPException

此模块中其他异常的基类。它是 Exception 的子类。

exception http.client.NotConnected

HTTPException 的子类。

exception http.client.InvalidURL

HTTPException 的子类,在给定的端口非数字或为空时引发。

exception http.client.UnknownProtocol

HTTPException 的子类。

exception http.client.UnknownTransferEncoding

HTTPException 的子类。

exception http.client.UnimplementedFileMode

HTTPException 的子类。

exception http.client.IncompleteRead

HTTPException 的子类。

exception http.client.ImproperConnectionState

HTTPException 的子类。

exception http.client.CannotSendRequest

ImproperConnectionState 的子类。

exception http.client.CannotSendHeader

ImproperConnectionState 的子类。

exception http.client.ResponseNotReady

ImproperConnectionState 的子类。

exception http.client.BadStatusLine

HTTPException 的子类。如果服务器响应了我们不理解的 HTTP 状态码,则会引发此异常。

exception http.client.LineTooLong

HTTPException 的子类。在从服务器接收到的 HTTP 协议中出现过长的行时引发。

exception http.client.RemoteDisconnected

ConnectionResetErrorBadStatusLine 的子类。由 HTTPConnection.getresponse() 在尝试读取响应时没有从连接中读取到任何数据时引发,这表明远程端已关闭连接。

在 3.5 版本加入: 以前,会引发 BadStatusLine('')

此模块中定义的常量是:

http.client.HTTP_PORT

HTTP 协议的默认端口(总是 80)。

http.client.HTTPS_PORT

HTTPS 协议的默认端口(总是 443)。

http.client.responses

此字典将 HTTP 1.1 状态码映射到 W3C 名称。

示例:http.client.responses[http.client.NOT_FOUND]'Not Found'

请参阅 HTTP 状态码 获取此模块中可作为常量的 HTTP 状态码列表。

HTTPConnection 对象

HTTPConnection 实例有以下方法:

HTTPConnection.request(method, url, body=None, headers={}, *, encode_chunked=False)

这将使用 HTTP 请求方法 method 和请求 URI url 向服务器发送请求。提供的 url 必须是绝对路径,以符合 RFC 2616 §5.1.2(除非连接到 HTTP 代理服务器或使用 OPTIONSCONNECT 方法)。

如果指定了 body,则在标头完成后发送指定的数据。它可以是一个 str、一个类字节对象、一个打开的文件对象,或者一个 bytes 的可迭代对象。如果 body 是一个字符串,它会以 ISO-8859-1 编码,这是 HTTP 的默认编码。如果它是一个类字节对象,则按原样发送字节。如果它是一个文件对象,则发送文件的内容;此文件对象应至少支持 read() 方法。如果文件对象是 io.TextIOBase 的实例,read() 方法返回的数据将以 ISO-8859-1 编码,否则 read() 返回的数据将按原样发送。如果 body 是一个可迭代对象,则可迭代对象的元素将按原样发送,直到可迭代对象耗尽。

headers 参数应该是一个与请求一起发送的额外 HTTP 标头的映射。必须提供一个 Host 标头,以符合 RFC 2616 §5.1.2(除非连接到 HTTP 代理服务器或使用 OPTIONSCONNECT 方法)。

如果 headers 中既不包含 Content-Length 也不包含 Transfer-Encoding,但存在请求体,则会自动添加其中一个标头字段。如果 bodyNone,对于需要主体的请求方法(PUTPOSTPATCH),Content-Length 标头将被设置为 0。如果 body 是一个字符串或一个非文件的类字节对象,Content-Length 标头将被设置为其长度。任何其他类型的 body(通常是文件和可迭代对象)将被分块编码,并且会自动设置 Transfer-Encoding 标头而不是 Content-Length。

encode_chunked 参数仅在 headers 中指定了 Transfer-Encoding 时才相关。如果 encode_chunkedFalse,HTTPConnection 对象假定所有编码都由调用代码处理。如果为 True,主体将被分块编码。

例如,要向 https://docs.pythonlang.cn/3/ 发送一个 GET 请求:

>>> import http.client
>>> host = "docs.python.org"
>>> conn = http.client.HTTPSConnection(host)
>>> conn.request("GET", "/3/", headers={"Host": host})
>>> response = conn.getresponse()
>>> print(response.status, response.reason)
200 OK

备注

分块传输编码已添加到 HTTP 协议 1.1 版本中。除非已知 HTTP 服务器能处理 HTTP 1.1,否则调用者必须指定 Content-Length,或者必须传递一个 str 或一个非文件的类字节对象作为主体表示。

在 3.2 版本发生变更: body 现在可以是一个可迭代对象。

在 3.6 版本发生变更: 如果 headers 中既未设置 Content-Length 也未设置 Transfer-Encoding,文件和可迭代的 body 对象现在会被分块编码。添加了 encode_chunked 参数。不会尝试为文件对象确定 Content-Length。

HTTPConnection.getresponse()

应在发送请求后调用,以获取服务器的响应。返回一个 HTTPResponse 实例。

备注

请注意,您必须在向服务器发送新请求之前读取完整的响应。

在 3.5 版本发生变更: 如果引发了 ConnectionError 或其子类,HTTPConnection 对象将在发送新请求时准备好重新连接。

HTTPConnection.set_debuglevel(level)

设置调试级别。默认调试级别为 0,表示不打印调试输出。任何大于 0 的值都会导致所有当前定义的调试输出打印到 stdout。debuglevel 会传递给任何新创建的 HTTPResponse 对象。

在 3.1 版本加入。

HTTPConnection.set_tunnel(host, port=None, headers=None)

设置用于 HTTP CONNECT 隧道的主机和端口。这允许通过代理服务器运行连接。

hostport 参数指定隧道连接的端点(即包含在 CONNECT 请求中的地址,而不是代理服务器的地址)。

headers 参数应该是一个与 CONNECT 请求一起发送的额外 HTTP 标头的映射。

根据 RFC 的规定,HTTP CONNECT 隧道请求使用 HTTP/1.1,因此必须提供一个 HTTP Host: 标头,该标头必须与作为 CONNECT 请求目标的 authority-form 形式的请求目标相匹配。如果未通过 headers 参数提供 HTTP Host: 标头,则会自动生成并传输一个。

例如,要通过在本地端口 8080 上运行的 HTTPS 代理服务器进行隧道,我们会将代理的地址传递给 HTTPSConnection 构造函数,并将我们最终想要访问的主机地址传递给 set_tunnel() 方法:

>>> import http.client
>>> conn = http.client.HTTPSConnection("localhost", 8080)
>>> conn.set_tunnel("www.python.org")
>>> conn.request("HEAD","/index.html")

在 3.2 版本加入。

在 3.12 版本发生变更: HTTP CONNECT 隧道请求使用 HTTP/1.1 协议,从 HTTP/1.0 协议升级而来。Host: HTTP 标头对于 HTTP/1.1 是强制性的,因此如果 headers 参数中未提供,将自动生成并传输一个。

HTTPConnection.get_proxy_response_headers()

返回一个字典,其中包含从代理服务器收到的对 CONNECT 请求的响应标头。

如果未发送 CONNECT 请求,则此方法返回 None

3.12 新版功能.

HTTPConnection.connect()

连接到创建对象时指定的服务器。默认情况下,如果客户端尚未建立连接,则在发出请求时会自动调用此方法。

引发一个 审计事件 http.client.connect,附带参数 self, host, port

HTTPConnection.close()

关闭与服务器的连接。

HTTPConnection.blocksize

用于发送类文件消息体的缓冲区大小(以字节为单位)。

在 3.7 版本加入。

作为使用上述 request() 方法的替代方案,您还可以通过使用下面的四个函数来逐步发送请求。

HTTPConnection.putrequest(method, url, skip_host=False, skip_accept_encoding=False)

这应该是与服务器建立连接后的第一个调用。它向服务器发送一行,包括 method 字符串、url 字符串和 HTTP 版本(HTTP/1.1)。要禁用自动发送 Host:Accept-Encoding: 标头(例如,为了接受额外的内容编码),请为 skip_hostskip_accept_encoding 指定非 False 值。

HTTPConnection.putheader(header, argument[, ...])

向服务器发送一个 RFC 822 风格的标头。它向服务器发送一行,包括标头、一个冒号和一个空格,以及第一个参数。如果给出更多参数,则会发送续行,每行由一个制表符和一个参数组成。

HTTPConnection.endheaders(message_body=None, *, encode_chunked=False)

向服务器发送一个空行,表示标头结束。可选的 message_body 参数可用于传递与请求相关的消息体。

如果 encode_chunkedTruemessage_body 的每次迭代结果将按照 RFC 7230 第 3.3.1 节的规定进行分块编码。数据的编码方式取决于 message_body 的类型。如果 message_body 实现了 缓冲区接口,编码将产生一个单独的数据块。如果 message_body 是一个 collections.abc.Iterablemessage_body 的每次迭代将产生一个数据块。如果 message_body 是一个文件对象,每次调用 .read() 将产生一个数据块。此方法在 message_body 结束后立即自动发出分块编码数据结束的信号。

备注

由于分块编码规范,迭代器主体产生的空块将被分块编码器忽略。这是为了避免由于格式错误的编码而导致目标服务器提前终止对请求的读取。

在 3.6 版本发生变更: 添加了分块编码支持和 encode_chunked 参数。

HTTPConnection.send(data)

向服务器发送数据。这应该仅在调用了 endheaders() 方法之后且在调用 getresponse() 之前直接使用。

引发一个 审计事件 http.client.send,附带参数 self, data

HTTPResponse 对象

一个 HTTPResponse 实例包装了来自服务器的 HTTP 响应。它提供了对请求标头和实体主体的访问。响应是一个可迭代对象,可以在 with 语句中使用。

在 3.5 版本发生变更: 现在实现了 io.BufferedIOBase 接口,并支持其所有的读取器操作。

HTTPResponse.read([amt])

读取并返回响应体,或者最多读取接下来的 amt 个字节。

HTTPResponse.readinto(b)

将响应体中最多接下来的 len(b) 个字节读入缓冲区 b。返回读取的字节数。

在 3.3 版本加入。

HTTPResponse.getheader(name, default=None)

返回标头 name 的值,如果没有匹配 name 的标头,则返回 default。如果存在多个同名 name 的标头,则返回所有值并用 ‘, ’ 连接。如果 default 是除单个字符串外的任何可迭代对象,其元素同样会用逗号连接后返回。

HTTPResponse.getheaders()

返回一个 (header, value) 元组列表。

HTTPResponse.fileno()

返回底层套接字的 fileno

HTTPResponse.msg

一个包含响应标头的 http.client.HTTPMessage 实例。http.client.HTTPMessageemail.message.Message 的子类。

HTTPResponse.version

服务器使用的 HTTP 协议版本。HTTP/1.0 为 10,HTTP/1.1 为 11。

HTTPResponse.url

所检索资源的 URL,通常用于确定是否发生了重定向。

HTTPResponse.headers

响应的标头,形式为 email.message.EmailMessage 实例。

HTTPResponse.status

服务器返回的状态码。

HTTPResponse.reason

服务器返回的原因短语。

HTTPResponse.debuglevel

一个调试钩子。如果 debuglevel 大于零,在读取和解析响应时,消息将被打印到 stdout。

HTTPResponse.closed

如果流已关闭,则为 True

HTTPResponse.geturl()

自 3.9 版本起已弃用: 已弃用,建议使用 url

HTTPResponse.info()

自 3.9 版本起已弃用: 已弃用,建议使用 headers

HTTPResponse.getcode()

自 3.9 版本起已弃用: 已弃用,建议使用 status

示例

以下是使用 GET 方法的示例会话:

>>> import http.client
>>> conn = http.client.HTTPSConnection("www.python.org")
>>> conn.request("GET", "/")
>>> r1 = conn.getresponse()
>>> print(r1.status, r1.reason)
200 OK
>>> data1 = r1.read()  # This will return entire content.
>>> # The following example demonstrates reading data in chunks.
>>> conn.request("GET", "/")
>>> r1 = conn.getresponse()
>>> while chunk := r1.read(200):
...     print(repr(chunk))
b'<!doctype html>\n<!--[if"...
...
>>> # Example of an invalid request
>>> conn = http.client.HTTPSConnection("docs.python.org")
>>> conn.request("GET", "/parrot.spam")
>>> r2 = conn.getresponse()
>>> print(r2.status, r2.reason)
404 Not Found
>>> data2 = r2.read()
>>> conn.close()

以下是使用 HEAD 方法的示例会话。请注意,HEAD 方法从不返回任何数据。

>>> import http.client
>>> conn = http.client.HTTPSConnection("www.python.org")
>>> conn.request("HEAD", "/")
>>> res = conn.getresponse()
>>> print(res.status, res.reason)
200 OK
>>> data = res.read()
>>> print(len(data))
0
>>> data == b''
True

以下是使用 POST 方法的示例会话:

>>> import http.client, urllib.parse
>>> params = urllib.parse.urlencode({'@number': 12524, '@type': 'issue', '@action': 'show'})
>>> headers = {"Content-type": "application/x-www-form-urlencoded",
...            "Accept": "text/plain"}
>>> conn = http.client.HTTPConnection("bugs.python.org")
>>> conn.request("POST", "", params, headers)
>>> response = conn.getresponse()
>>> print(response.status, response.reason)
302 Found
>>> data = response.read()
>>> data
b'Redirecting to <a href="https://bugs.python.org/issue12524">https://bugs.python.org/issue12524</a>'
>>> conn.close()

客户端的 HTTP PUT 请求与 POST 请求非常相似。区别仅在于服务器端,HTTP 服务器会允许通过 PUT 请求创建资源。需要注意的是,自定义 HTTP 方法也在 urllib.request.Request 中通过设置相应的方法属性来处理。以下是使用 PUT 方法的示例会话:

>>> # This creates an HTTP request
>>> # with the content of BODY as the enclosed representation
>>> # for the resource https://:8080/file
...
>>> import http.client
>>> BODY = "***filecontents***"
>>> conn = http.client.HTTPConnection("localhost", 8080)
>>> conn.request("PUT", "/file", BODY)
>>> response = conn.getresponse()
>>> print(response.status, response.reason)
200, OK

HTTPMessage 对象

class http.client.HTTPMessage(email.message.Message)

一个 http.client.HTTPMessage 实例持有来自 HTTP 响应的标头。它是使用 email.message.Message 类实现的。