21.12. http.client — HTTP 协议客户端 — Python 文档
21.12. 客户端 — HTTP 协议客户端
源代码: :source:`Lib/http/client.py`
该模块定义了实现 HTTP 和 HTTPS 协议客户端的类。 它通常不直接使用——模块 urllib.request 使用它来处理使用 HTTP 和 HTTPS 的 URL。
该模块提供以下类:
- class http.client.HTTPConnection(host, port=None, [timeout, ]source_address=None)
HTTPConnection 实例表示与 HTTP 服务器的一个事务。 它应该被实例化并传递一个主机和可选的端口号。 如果未传递端口号,则从主机字符串中提取端口(如果其格式为
host:port
),否则使用默认 HTTP 端口 (80)。 如果给出了可选的 timeout 参数,阻塞操作(如连接尝试)将在该秒后超时(如果未给出,则使用全局默认超时设置)。 可选的 source_address 参数可以是(主机,端口)的元组,用作建立 HTTP 连接的源地址。例如,以下调用所有在同一主机和端口连接到服务器的创建实例:
>>> 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 风格的“简单响应”。
- class http.client.HTTPSConnection(host, port=None, key_file=None, cert_file=None, [timeout, ]source_address=None, *, context=None, check_hostname=None)
HTTPConnection 的子类,它使用 SSL 与安全服务器进行通信。 默认端口为
443
。 如果指定了 context,它必须是一个描述各种 SSL 选项的 ssl.SSLContext 实例。有关最佳实践的更多信息,请阅读 安全注意事项 。
3.2 版更改:添加了 source_address、context 和 check_hostname。
3.2 版更改: 该类现在在可能的情况下支持 HTTPS 虚拟主机(即,如果 ssl.HAS_SNI 为 true)。
3.4 版更改: 删除了 strict 参数。 不再支持 HTTP 0.9 风格的“简单响应”。
3.4.3 版更改: 该类现在默认执行所有必要的证书和主机名检查。 要恢复到之前未验证的行为
ssl._create_unverified_context()
,可以将其传递给 context 参数。自 3.6 版起已弃用:key_file 和 cert_file 已弃用,以支持 context。 请改用 ssl.SSLContext.load_cert_chain(),或让 ssl.create_default_context() 为您选择系统的可信 CA 证书。
check_hostname 参数也已弃用; 应改用 context 的 ssl.SSLContext.check_hostname 属性。
- class http.client.HTTPResponse(sock, debuglevel=0, method=None, url=None)
成功连接后返回其实例的类。 不是由用户直接实例化。
3.4 版更改: 删除了 strict 参数。 不再支持 HTTP 0.9 风格的“简单响应”。
会酌情引发以下异常:
- 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
ConnectionResetError 和 BadStatusLine 的子类。 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 状态代码列表。
21.12.1. HTTPConnection 对象
HTTPConnection 实例有以下方法:
- HTTPConnection.request(method, url, body=None, headers={}, *, encode_chunked=False)
这将使用 HTTP 请求方法 method 和选择器 url 向服务器发送请求。
如果指定了 body,则在 headers 完成后发送指定的数据。 它可能是一个 str、一个 bytes-like object、一个打开的 file object,或者一个 bytes 的可迭代对象。 如果 body 是一个字符串,它被编码为 ISO-8859-1,这是 HTTP 的默认值。 如果它是一个类似字节的对象,则按原样发送字节。 如果是文件对象,则发送文件内容; 这个文件对象至少应该支持
read()
方法。 如果文件对象是io.TextIOBase的实例,则read()
方法返回的数据将编码为ISO-8859-1,否则read()
方法返回的数据] 按原样发送。 如果 body 是可迭代对象,则可迭代对象的元素将按原样发送,直到用完可迭代对象。headers 参数应该是与请求一起发送的额外 HTTP 标头的映射。
如果 headers 既不包含 Content-Length 也不包含 Transfer-Encoding,但有一个请求体,这些头字段之一将被自动添加。 如果 body 是
None
,则 Content-Length 标头设置为0
,用于期望主体的方法 (PUT
,POST
,和PATCH
)。 如果 body 是一个字符串或类似字节的对象,但不是 file,则 Content-Length 标头设置为其长度。 任何其他类型的 body(一般的文件和可迭代对象)都将进行块编码,并且将自动设置 Transfer-Encoding 标头而不是 Content-Length。encode_chunked 参数只有在 headers 中指定了 Transfer-Encoding 时才相关。 如果 encode_chunked 是
False
,则 HTTPConnection 对象假定所有编码都由调用代码处理。 如果是True
,则正文将被块编码。笔记
分块传输编码已添加到 HTTP 协议 1.1 版中。 除非已知 HTTP 服务器处理 HTTP 1.1,否则调用者必须指定 Content-Length,或者必须传递一个 str 或类似字节的对象,该对象也不是文件作为主体表示。
3.2 版新功能:body 现在可以是一个可迭代对象。
3.6 版更改: 如果在 headers 中既没有设置 Content-Length 也没有设置 Transfer-Encoding,文件和可迭代的 body 对象现在是块编码的。 添加了 encode_chunked 参数。 不尝试确定文件对象的内容长度。
- HTTPConnection.getresponse()
应在发送请求以从服务器获取响应后调用。 返回一个 HTTPResponse 实例。
笔记
请注意,您必须先阅读整个响应,然后才能向服务器发送新请求。
3.5 版更改: 如果引发 ConnectionError 或子类,则 HTTPConnection 对象将准备好在发送新请求时重新连接。
- HTTPConnection.set_debuglevel(level)
设置调试级别。 默认调试级别为
0
,表示不打印调试输出。 任何大于0
的值都会导致所有当前定义的调试输出打印到标准输出。debuglevel
被传递给任何新创建的 HTTPResponse 对象。3.1 版中的新功能。
- HTTPConnection.set_tunnel(host, port=None, headers=None)
设置 HTTP 连接隧道的主机和端口。 这允许通过代理服务器运行连接。
主机和端口参数指定隧道连接的端点(即 CONNECT 请求中包含的地址, 不是 代理服务器的地址)。
headers 参数应该是与 CONNECT 请求一起发送的额外 HTTP 标头的映射。
例如,要通过在本地运行的 8080 端口上的 HTTPS 代理服务器进行隧道传输,我们会将代理的地址传递给 HTTPSConnection 构造函数,并将我们最终想要访问的主机地址传递给 HTTPSConnection X234X]set_tunnel() 方法:
>>> import http.client >>> conn = http.client.HTTPSConnection("localhost", 8080) >>> conn.set_tunnel("www.python.org") >>> conn.request("HEAD","/index.html")
3.2 版中的新功能。
- HTTPConnection.connect()
- 连接到创建对象时指定的服务器。 默认情况下,如果客户端还没有连接,则在发出请求时会自动调用它。
- HTTPConnection.close()
- 关闭与服务器的连接。
作为使用上述 request()
方法的替代方法,您还可以使用以下四个功能逐步发送您的请求。
- HTTPConnection.putrequest(method, url, skip_host=False, skip_accept_encoding=False)
- 这应该是连接到服务器后的第一次调用。 它向服务器发送一行由 method 字符串、url 字符串和 HTTP 版本(
HTTP/1.1
)组成的行。 要禁用Host:
或Accept-Encoding:
标头的自动发送(例如接受其他内容编码),请使用非 False 值指定 skip_host 或 skip_accept_encoding .
- HTTPConnection.putheader(header, argument[, ...])
- 向服务器发送 RFC 822 样式的标头。 它向服务器发送一行,由标题、冒号和空格以及第一个参数组成。 如果给出更多参数,则发送续行行,每个行由一个制表符和一个参数组成。
- HTTPConnection.endheaders(message_body=None, *, encode_chunked=False)
向服务器发送一个空行,表示标头结束。 可选的 message_body 参数可用于传递与请求关联的消息正文。
如果 encode_chunked 是
True
,则 message_body 每次迭代的结果将按照 RFC 7230 中的规定进行块编码],第 3.3.1 节。 数据的编码方式取决于 message_body 的类型。 如果 message_body 实现了 buffer interface,则编码将导致单个块。 如果 message_body 是一个collections.Iterable
,则 message_body 的每次迭代都会产生一个块。 如果 message_body 是一个 文件对象 ,则每次调用.read()
都会产生一个块。 该方法会在 message_body 之后立即自动发出块编码数据的结束信号。笔记
由于分块编码规范,迭代器主体产生的空块将被块编码器忽略。 这是为了避免目标服务器由于编码格式错误而过早终止对请求的读取。
3.6 新功能:分块编码支持。 添加了 encode_chunked 参数。
- HTTPConnection.send(data)
- 向服务器发送数据。 只有在调用 endheaders() 方法之后和调用 getresponse() 之前,才应该直接使用它。
21.12.2. 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.HTTPMessage
是 email.message.Message 的子类。
- HTTPResponse.version
- 服务器使用的 HTTP 协议版本。 HTTP/1.0 为 10,HTTP/1.1 为 11。
- HTTPResponse.status
- 服务器返回的状态码。
- HTTPResponse.reason
- 服务器返回的原因短语。
- HTTPResponse.debuglevel
- 一个调试钩子。 如果 debuglevel 大于零,则在读取和解析响应时消息将打印到标准输出。
- HTTPResponse.closed
- 如果流已关闭,则为
True
。
21.12.3. 例子
以下是使用 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 not r1.closed:
... print(r1.read(200)) # 200 bytes
b'<!doctype html>\n<!--[if"...
...
>>> # Example of an invalid request
>>> 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="http://bugs.python.org/issue12524">http://bugs.python.org/issue12524</a>'
>>> conn.close()
客户端 HTTP PUT
请求与 POST
请求非常相似。 区别仅在于服务器端,HTTP 服务器允许通过 PUT
请求创建资源。 应该注意的是,自定义 HTTP 方法也在 urllib.request.Request 中通过发送适当的 +method 属性来处理。这是一个示例会话,展示了如何使用 PUT
请求http.客户端:
>>> # This creates an HTTP message
>>> # 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