客户
¥Clients
暗示
¥Hint
如果您来自 Requests,httpx.Client()你可以用什么来代替requests.Session()。
¥If you are coming from Requests, httpx.Client() is what you can use instead of requests.Session().
为什么要使用客户端?
¥Why use a Client?
TL;DR
¥TL;DR
如果你做的不仅仅是实验、一次性脚本或原型,那么你应该使用Client实例。
¥If you do anything more than experimentation, one-off scripts, or prototypes, then you should use a Client instance.
更有效地利用网络资源
¥More efficient usage of network resources
当您使用顶级 API 发出请求时,如快速入门指南,HTTPX 必须建立新的连接对于每个请求(连接不被重用)。随着对主机的请求数量的增加,这种方法很快就会变得效率低下。
¥When you make requests using the top-level API as documented in the Quickstart guide, HTTPX has to establish a new connection for every single request (connections are not reused). As the number of requests to a host increases, this quickly becomes inefficient.
另一方面,Client实例用途HTTP 连接池。这意味着,当你向同一主机发出多个请求时,Client将重用底层 TCP 连接,而不是为每个请求重新创建一个连接。
¥On the other hand, a Client instance uses HTTP connection pooling. This means that when you make several requests to the same host, the Client will reuse the underlying TCP connection, instead of recreating one for every single request.
这可以带来显著的性能改进与使用顶级 API 相比,包括:
¥This can bring significant performance improvements compared to using the top-level API, including:
减少请求的延迟(无需握手)。
¥Reduced latency across requests (no handshaking).
减少 CPU 使用率和往返次数。
¥Reduced CPU usage and round-trips.
减少网络拥塞。
¥Reduced network congestion.
额外功能
¥Extra features
Client实例还支持顶级 API 所不具备的功能,例如:
¥Client instances also support features that aren't available at the top-level API, such as:
跨请求的 Cookie 持久性。
¥Cookie persistence across requests.
对所有传出的请求应用配置。
¥Applying configuration across all outgoing requests.
通过 HTTP 代理发送请求。
¥Sending requests through HTTP proxies.
使用HTTP/2。
¥Using HTTP/2.
本页的其他部分进一步详细介绍了如何使用Client实例。
¥The other sections on this page go into further detail about what you can do with a Client instance.
用法
¥Usage
推荐使用Client是上下文管理器。这将确保在离开时正确清理连接with堵塞:
¥The recommended way to use a Client is as a context manager. This will ensure that connections are properly cleaned up when leaving the with block:
with httpx.Client() as client:
...
或者,您可以使用以下方法显式关闭连接池,而无需阻止使用.close():
¥Alternatively, you can explicitly close the connection pool without block-usage using .close():
client = httpx.Client()
try:
...
finally:
client.close()
发出请求
¥Making requests
一旦你有Client,您可以使用发送请求.get(),.post()等。例如:
¥Once you have a Client, you can send requests using .get(), .post(), etc. For example:
>>> with httpx.Client() as client:
... r = client.get('https://example.com')
...
>>> r
<Response [200 OK]>
这些方法接受与httpx.get(),httpx.post()等。这意味着快速入门客户端级别也提供指南。
¥These methods accept the same arguments as httpx.get(), httpx.post(), etc. This means that all features documented in the Quickstart guide are also available at the client level.
例如,发送带有自定义标头的请求:
¥For example, to send a request with custom headers:
>>> with httpx.Client() as client:
... headers = {'X-Custom': 'value'}
... r = client.get('https://example.com', headers=headers)
...
>>> r.request.headers['X-Custom']
'value'
跨请求共享配置
¥Sharing configuration across requests
客户端允许您通过将参数传递给Client构造函数。
¥Clients allow you to apply configuration to all outgoing requests by passing parameters to the Client constructor.
例如,要应用一组自定义标头每次请求:
¥For example, to apply a set of custom headers on every request:
>>> url = 'http://httpbin.org/headers'
>>> headers = {'user-agent': 'my-app/0.0.1'}
>>> with httpx.Client(headers=headers) as client:
... r = client.get(url)
...
>>> r.json()['headers']['User-Agent']
'my-app/0.0.1'
合并配置
¥Merging of configuration
当在客户端级别和请求级别都提供配置选项时,可能会发生以下两种情况之一:
¥When a configuration option is provided at both the client-level and request-level, one of two things can happen:
对于标头、查询参数和 Cookie,这些值会组合在一起。例如:
¥For headers, query parameters and cookies, the values are combined together. For example:
>>> headers = {'X-Auth': 'from-client'}
>>> params = {'client_id': 'client1'}
>>> with httpx.Client(headers=headers, params=params) as client:
... headers = {'X-Custom': 'from-request'}
... params = {'request_id': 'request1'}
... r = client.get('https://example.com', headers=headers, params=params)
...
>>> r.request.url
URL('https://example.com?client_id=client1&request_id=request1')
>>> r.request.headers['X-Auth']
'from-client'
>>> r.request.headers['X-Custom']
'from-request'
对于所有其他参数,请求级值优先。例如:
¥For all other parameters, the request-level value takes priority. For example:
>>> with httpx.Client(auth=('tom', 'mot123')) as client:
... r = client.get('https://example.com', auth=('alice', 'ecila123'))
...
>>> _, _, auth = r.request.headers['Authorization'].partition(' ')
>>> import base64
>>> base64.b64decode(auth)
b'alice:ecila123'
如果您需要对客户端级别和请求级别参数的合并进行更细粒度的控制,请参阅请求实例。
¥If you need finer-grained control on the merging of client-level and request-level parameters, see Request instances.
其他仅限客户端的配置选项
¥Other Client-only configuration options
此外,Client接受一些在请求级别不可用的配置选项。
¥Additionally, Client accepts some configuration options that aren't available at the request level.
例如,base_url允许您在所有传出的请求前添加一个 URL:
¥For example, base_url allows you to prepend an URL to all outgoing requests:
>>> with httpx.Client(base_url='http://httpbin.org') as client:
... r = client.get('/headers')
...
>>> r.request.url
URL('http://httpbin.org/headers')
有关所有可用客户端参数的列表,请参阅ClientAPI 参考。
¥For a list of all available client parameters, see the Client API reference.
请求实例
¥Request instances
为了最大程度地控制通过网络发送的内容,HTTPX 支持构建显式Request实例:
¥For maximum control on what gets sent over the wire, HTTPX supports building explicit Request instances:
request = httpx.Request("GET", "https://example.com")
派遣Request实例通过网络,创建一个Client实例并使用.send():
¥To dispatch a Request instance across to the network, create a Client instance and use .send():
with httpx.Client() as client:
response = client.send(request)
...
如果您需要以默认不支持的方式混合客户端级别和请求级别选项参数合并,你可以使用.build_request()然后对Request实例。例如:
¥If you need to mix client-level and request-level options in a way that is not supported by the default Merging of parameters, you can use .build_request() and then make arbitrary modifications to the Request instance. For example:
headers = {"X-Api-Key": "...", "X-Client-ID": "ABC123"}
with httpx.Client(headers=headers) as client:
request = client.build_request("GET", "https://api.example.com")
print(request.headers["X-Client-ID"]) # "ABC123"
# Don't send the API key for this particular request.
del request.headers["X-Api-Key"]
response = client.send(request)
...
监控下载进度
¥Monitoring download progress
如果您需要监视大型响应的下载进度,则可以使用响应流并检查response.num_bytes_downloaded财产。
¥If you need to monitor download progress of large responses, you can use response streaming and inspect the response.num_bytes_downloaded property.
此接口对于正确确定下载进度是必需的,因为response.content或者response.iter_content()如果使用 HTTP 响应压缩,将并不总是与响应的原始内容长度相对应。
¥This interface is required for properly determining download progress, because the total number of bytes returned by response.content or response.iter_content() will not always correspond with the raw content length of the response if HTTP response compression is being used.
例如,使用tqdm在下载响应时库可以这样做……
¥For example, showing a progress bar using the tqdm library while a response is being downloaded could be done like this…
import tempfile
import httpx
from tqdm import tqdm
with tempfile.NamedTemporaryFile() as download_file:
url = "https://speed.hetzner.de/100MB.bin"
with httpx.stream("GET", url) as response:
total = int(response.headers["Content-Length"])
with tqdm(total=total, unit_scale=True, unit_divisor=1024, unit="B") as progress:
num_bytes_downloaded = response.num_bytes_downloaded
for chunk in response.iter_bytes():
download_file.write(chunk)
progress.update(response.num_bytes_downloaded - num_bytes_downloaded)
num_bytes_downloaded = response.num_bytes_downloaded

或者另一个例子,这次使用rich图书馆…
¥Or an alternate example, this time using the rich library…
import tempfile
import httpx
import rich.progress
with tempfile.NamedTemporaryFile() as download_file:
url = "https://speed.hetzner.de/100MB.bin"
with httpx.stream("GET", url) as response:
total = int(response.headers["Content-Length"])
with rich.progress.Progress(
"[progress.percentage]{task.percentage:>3.0f}%",
rich.progress.BarColumn(bar_width=None),
rich.progress.DownloadColumn(),
rich.progress.TransferSpeedColumn(),
) as progress:
download_task = progress.add_task("Download", total=total)
for chunk in response.iter_bytes():
download_file.write(chunk)
progress.update(download_task, completed=response.num_bytes_downloaded)

监控上传进度
¥Monitoring upload progress
如果需要监控大型响应的上传进度,可以使用请求内容生成器流。
¥If you need to monitor upload progress of large responses, you can use request content generator streaming.
例如,使用tqdm图书馆。
¥For example, showing a progress bar using the tqdm library.
import io
import random
import httpx
from tqdm import tqdm
def gen():
"""
this is a complete example with generated random bytes.
you can replace `io.BytesIO` with real file object.
"""
total = 32 * 1024 * 1024 # 32m
with tqdm(ascii=True, unit_scale=True, unit='B', unit_divisor=1024, total=total) as bar:
with io.BytesIO(random.randbytes(total)) as f:
while data := f.read(1024):
yield data
bar.update(len(data))
httpx.post("https://httpbin.org/post", content=gen())

多部分文件编码
¥Multipart file encoding
正如快速入门通过传递一个字典来实现多部分文件编码,该字典以有效负载的名称作为键,以元素元组或类似文件的对象或字符串作为值。
¥As mentioned in the quickstart multipart file encoding is available by passing a dictionary with the name of the payloads as keys and either tuple of elements or a file-like object or a string as values.
>>> with open('report.xls', 'rb') as report_file:
... files = {'upload-file': ('report.xls', report_file, 'application/vnd.ms-excel')}
... r = httpx.post("https://httpbin.org/post", files=files)
>>> print(r.text)
{
...
"files": {
"upload-file": "<... binary content ...>"
},
...
}
更具体地说,如果使用元组作为值,则它必须具有 2 到 3 个元素:
¥More specifically, if a tuple is used as a value, it must have between 2 and 3 elements:
第一个元素是可选文件名,可以设置为
None。¥The first element is an optional file name which can be set to
None.第二个元素可以是文件类对象或字符串,它将自动以 UTF-8 编码。
¥The second element may be a file-like object or a string which will be automatically encoded in UTF-8.
可选的第三个元素可用于指定MIME 类型正在上传的文件。如果未指定,HTTPX 将尝试根据文件名猜测 MIME 类型,未知文件扩展名默认为“application/octet-stream”。如果文件名明确设置为
None那么 HTTPX 将不包含内容类型 MIME 标头字段。¥An optional third element can be used to specify the MIME type of the file being uploaded. If not specified HTTPX will attempt to guess the MIME type based on the file name, with unknown file extensions defaulting to "application/octet-stream". If the file name is explicitly set to
Nonethen HTTPX will not include a content-type MIME header field.
>>> files = {'upload-file': (None, 'text content', 'text/plain')}
>>> r = httpx.post("https://httpbin.org/post", files=files)
>>> print(r.text)
{
...
"files": {},
"form": {
"upload-file": "text-content"
},
...
}
提示
¥Tip
通过这种方式上传大文件是安全的。文件上传默认是流式的,这意味着一次只会将一个块加载到内存中。
¥It is safe to upload large files this way. File uploads are streaming by default, meaning that only one chunk will be loaded into memory at a time.
非文件数据字段可以通过将它们传递给包含在多部分表单中data=...。
¥Non-file data fields can be included in the multipart form using by passing them to data=....
您还可以使用多文件字段表单一次性发送多个文件。为此,请传递一个列表(field, <file>)items 而不是字典,允许你传递相同的多个项目field。例如,此请求发送 2 个文件,foo.png和bar.png在一个请求中images表单字段:
¥You can also send multiple files in one go with a multiple file field form.
To do that, pass a list of (field, <file>) items instead of a dictionary, allowing you to pass multiple items with the same field.
For instance this request sends 2 files, foo.png and bar.png in one request on the images form field:
>>> with open('foo.png', 'rb') as foo_file, open('bar.png', 'rb') as bar_file:
... files = [
... ('images', ('foo.png', foo_file, 'image/png')),
... ('images', ('bar.png', bar_file, 'image/png')),
... ]
... r = httpx.post("https://httpbin.org/post", files=files)