http.client — HTTP 协议客户端

源代码: Lib/http/client.py


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

另请参阅

推荐使用 Requests 包 作为更高级别的 HTTP 客户端接口。

注意

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

可用性:不支持 Emscripten,不支持 WASI。

此模块在 WebAssembly 平台 wasm32-emscriptenwasm32-wasi 上不可用或无法工作。有关更多信息,请参阅 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 选项的 ssl.SSLContext 实例。

有关最佳实践的更多信息,请阅读 安全注意事项

在 3.2 版更改: 添加了 source_addresscontextcheck_hostname

在 3.2 版更改: 如果可能(即,如果 ssl.HAS_SNI 为真),此类现在支持 HTTPS 虚拟主机。

在 3.4 版更改: 删除了 strict 参数。不再支持 HTTP 0.9 风格的“简单响应”。

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

在 3.8 版更改: 此类现在为默认 context 或在使用自定义 context 传递 cert_file 时启用 TLS 1.3 ssl.SSLContext.post_handshake_auth

在 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 行。该文件必须准备好读取这些字段行,因此在调用该函数之前,应该已经读取了第一行。

将根据情况引发以下异常

异常 http.client.HTTPException

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

异常 http.client.NotConnected

HTTPException 的子类。

异常 http.client.InvalidURL

HTTPException 的子类,如果给定的端口是非数字或为空,则会引发此异常。

异常 http.client.UnknownProtocol

HTTPException 的子类。

异常 http.client.UnknownTransferEncoding

HTTPException 的子类。

异常 http.client.UnimplementedFileMode

HTTPException 的子类。

异常 http.client.IncompleteRead

HTTPException 的子类。

异常 http.client.ImproperConnectionState

HTTPException 的子类。

异常 http.client.CannotSendRequest

ImproperConnectionState 的子类。

异常 http.client.CannotSendHeader

ImproperConnectionState 的子类。

异常 http.client.ResponseNotReady

ImproperConnectionState 的子类。

异常 http.client.BadStatusLine

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

异常 http.client.LineTooLong

HTTPException 的子类。如果从服务器收到的 HTTP 协议中的行过长,则会引发此异常。

异常 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 隧道的 host 和 port。这允许连接通过代理服务器运行。

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

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

由于 HTTP/1.1 用于 HTTP CONNECT 隧道请求,根据 RFC,必须提供 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()

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

使用参数 selfhostport 引发带有参数的 审计事件 http.client.connect

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: 标头(例如,要接受其他内容编码),请使用非 False 值指定 skip_hostskip_accept_encoding

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

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

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

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

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

注意

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

3.6 版更改: 添加了分块编码支持和 encode_chunked 参数。

HTTPConnection.send(data)

向服务器发送数据。只有在调用 endheaders() 方法之后和调用 getresponse() 之前,才应该直接使用此方法。

使用参数 selfdata 引发 审计事件 http.client.send

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 协议版本。10 表示 HTTP/1.0,11 表示 HTTP/1.1。

HTTPResponse.url

检索到的资源的 URL,通常用于确定是否进行了重定向。

HTTPResponse.headers

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

HTTPResponse.status

服务器返回的状态码。

HTTPResponse.reason

服务器返回的原因短语。

HTTPResponse.debuglevel

调试钩子。如果 debuglevel 大于零,则在读取和解析响应时,消息将打印到标准输出。

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 http://localhost: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 类实现的。