http.client — HTTP 协议客户端

源代码: Lib/http/client.py


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

参见

建议使用 Requests 包 来获得更高级别的 HTTP 客户端接口。

备注

只有在 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 选项的 ssl.SSLContext 实例。

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

在 3.2 版本中更改: 添加了 *source_address*、*context* 和 *check_hostname*。

在 3.2 版本中更改: 如果可能(即,如果 ssl.HAS_SNI 为 true),此类现在支持 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_file*、*cert_file* 和 *check_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 的子类。

异常 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。

只有在 headers 中指定了 Transfer-Encoding 时,encode_chunked 参数才相关。 如果 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 或类似字节的对象(而不是文件)作为 body 的表示。

在 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 参数应该是一个额外的 HTTP 标头映射,用于随 CONNECT 请求一起发送。

由于 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()

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

引发一个 审计事件 http.client.connect,参数为 selfhostport

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

备注

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

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

HTTPConnection.send(data)

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

引发带有参数 self, data审计事件 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 协议版本。 HTTP/1.0 为 10,HTTP/1.1 为 11。

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 请求创建资源。 应当注意的是,通过设置适当的方法属性,也可以在 urllib.request.Request 中处理自定义 HTTP 方法。 这是一个使用 PUT 方法的会话示例

>>> # This creates an HTTP request
>>> # with the content of BODY as the enclosed representation
>>> # for the resource https://127.0.0.1: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 类实现。