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

源码: Lib/http/client.py

本模块定义了HTTP和HTTPS协议的客户端实现。通常来说,该模块不能直接使用,需要模块urllib.request调用该模块来处理使用HTTP和HTTPS的URL。

参考

推荐使用Requests package包处理高级别HTTP客户端接口。

注意

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

本模块提供以下类:

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

一个 HTTPConnection实例表示与HTTP服务器端的一次事务。通过传参host地址和端口号进行实例化。没有端口号传参,也可以通过host传参,形式同host:port,都没有的话,默认端口号为80。如果可选参数 timeout给出传参,阻塞操作(如连接)将在给出的秒数后超时(如果未给出该参数,默认使用全局默认超时设置值)。可选参数source_address可以是一个元组,形式同 (host, port),作为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中已更改:已删除严格参数。不再支持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.SSLContext实例化,它用于描述不同的SSL选项。

key_filecert_file已被弃用,请改用ssl.SSLContext.load_cert_chain()或让ssl.create_default_context()为您选择系统的受信任的CA证书。check_hostname参数也已弃用;应使用上下文ssl.SSLContext.check_hostname属性。

有关最佳做法的详情,请参阅Security considerations

在版本3.2中更改: 源地址上下文check_hostname已添加。

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

在版本3.4中已更改:已删除严格参数。不再支持HTTP 0.9样式的“简单响应”。

在版本3.4.3中更改:此类现在默认执行所有必需的证书和主机名检查。要还原到上一个未验证的行为,ssl._create_unverified_context()可以传递到上下文参数。

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

该类是在连接成功后返回的实例。不需要用户直接实例化。

在版本3.4中已更改:已删除严格参数。不再支持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

该字典类匹配HTTP1.1状态码在W3C中的命名。

Example: http.client.responses[http.client.NOT_FOUND] 就是 'Not Found'.

本模块中HTTP状态码的常量值列表可参考HTTP status codes

21.12.1. HTTPConnection对象

HTTPConnection 实例拥有方法如下:

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

该方法会向服务器端发送一个请求,入参为HTTP请求方法method和选择器url

如果指定了入参body ,那么在 headers发送完成后就发送body的数据。它可能是一个字符串、 一个 类似字节对象、 打开的 文件对象,或可迭代的 类似字节对象 。如果 body 是一个字符串,它按 ISO-8859-1进行编码,默认 HTTP 。如果body是一个类似字节对象,按字节发送。如果body是一个 文件对象,发送的是文件的内容;这个文件对象至少可支持 read() 方法。If the file object has a mode attribute, the data returned by the read() method will be encoded as ISO-8859-1 unless the mode attribute contains the substring b, otherwise the data returned by read() is sent as is. 如果body是可迭代的,则可迭代的元素按照原样发送,直到可迭代被耗尽。

参数 headers 应该是附带的HTTP报文头的映射,与请求一起发送。

如果参数 headers 不包括内容长度项,那么就自动添加一个。如果bodyNone,那么对于需要body的方法(PUT),Content-Length标头设置为0POSTPATCH)。如果body是字符串或字节对象,则将Content-Length头设置为其长度。如果body是一个file object,并且它的作用是对fileno()的结果调用fstat()方法,那么Content-Length头部被设置为由fstat调用报告的st_size否则不添加Content-Length头。

版本3.2中的新功能: 正文现在可以是可迭代的。

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隧道的主机和端口。这允许通过代理服务器运行连接。

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

headers参数应该是使用CONNECT请求发送的额外HTTP头的映射。

例如,要通过在端口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中的新功能。

HTTPConnection.connect()

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

HTTPConnection.close()

关闭与服务器的连接。

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

HTTPConnection.putrequest(request, selector, skip_host=False, skip_accept_encoding=False)

这应该是在连接到服务器之后的第一个调用。它向由请求字符串,选择器字符串和HTTP版本(HTTP/1.1)组成的服务器发送一行。要禁止自动发送Host:Accept-Encoding:标头(例如接受附加内容编码),请指定skip_hostskip_accept_encoding与非False值。

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

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

HTTPConnection.endheaders(message_body=None)

发送空白行到服务器,用信号通知头的结束。可选的message_body参数可用于传递与请求相关联的消息体。如果消息头是字符串,消息体将与消息头在相同的分组中发送,否则它将在单独的分组中发送。

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'是除了单个字符串之外的任何可迭代,它的元素类似地返回用逗号连接。

HTTPResponse.getheaders()

返回(标题,值)元组的列表。

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.status

服务器返回的状态代码。

HTTPResponse.reason

服务器返回的原因短语。

HTTPResponse.debuglevel

调试挂钩。如果debuglevel大于零,则会在读取和解析响应时将消息打印到stdout。

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中处理。这是一个示例会话,显示如何做PUT

>>> # 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

21.12.4. HTTPMessage对象

http.client.HTTPMessage实例保存来自HTTP响应的标头。它使用email.message.Message类实现。