异步支持
HTTPX 默认提供标准的同步 API,但同时也为您提供了异步客户端选项(如果需要)。
异步是一种比多线程更高效的并发模型,能带来显著的性能优势,并支持使用长连接网络协议(如 WebSockets)。
如果您正在使用异步 Web 框架,那么您也会希望使用异步客户端来发送外发 HTTP 请求。
发起异步请求
要发起异步请求,您需要一个 AsyncClient
。
>>> async with httpx.AsyncClient() as client:
... r = await client.get('https://www.example.com/')
...
>>> r
<Response [200 OK]>
提示
使用 IPython 或 Python 3.9+ 配合 python -m asyncio
来交互式运行此代码,因为它们支持在控制台中执行 async
/await
表达式。
API 差异
如果您使用异步客户端,那么有几个 API 会使用异步方法。
发起请求
所有请求方法都是异步的,因此对于以下所有方法,您都应该使用 response = await client.get(...)
这种形式:
AsyncClient.get(url, ...)
AsyncClient.options(url, ...)
AsyncClient.head(url, ...)
AsyncClient.post(url, ...)
AsyncClient.put(url, ...)
AsyncClient.patch(url, ...)
AsyncClient.delete(url, ...)
AsyncClient.request(method, url, ...)
AsyncClient.send(request, ...)
打开和关闭客户端
如果需要使用上下文管理的客户端,请使用 async with httpx.AsyncClient()
...
async with httpx.AsyncClient() as client:
...
Warning
为了充分利用连接池的优势,请确保不要实例化多个客户端实例——例如在"热循环"中使用 async with
。可以通过以下方式实现:使用一个在需要处传递的作用域内客户端,或者使用一个全局客户端实例。
或者,如果需要显式关闭客户端,可以使用 await client.aclose()
:
client = httpx.AsyncClient()
...
await client.aclose()
流式响应
AsyncClient.stream(method, url, ...)
方法是一个异步上下文块。
>>> client = httpx.AsyncClient()
>>> async with client.stream('GET', 'https://www.example.com/') as response:
... async for chunk in response.aiter_bytes():
... ...
异步响应流式处理方法包括:
Response.aread()
- 用于在流式块中有条件地读取响应Response.aiter_bytes()
- 以字节形式流式传输响应内容Response.aiter_text()
- 以文本形式流式传输响应内容Response.aiter_lines()
- 以文本行的形式流式传输响应内容Response.aiter_raw()
- 流式传输原始响应字节,不应用内容解码Response.aclose()
- 关闭响应。通常不需要手动调用,因为.stream
块会在退出时自动关闭响应
当上下文块使用不切实际时,可以通过使用 client.send(..., stream=True)
发送一个 Request
实例 来进入"手动模式"。
以下示例展示了如何在使用 Starlette 时将响应转发到流式 Web 端点:
import httpx
from starlette.background import BackgroundTask
from starlette.responses import StreamingResponse
client = httpx.AsyncClient()
async def home(request):
req = client.build_request("GET", "https://www.example.com/")
r = await client.send(req, stream=True)
return StreamingResponse(r.aiter_text(), background=BackgroundTask(r.aclose))
警告
当使用这种"手动流式模式"时,开发者有责任确保最终调用 Response.aclose()
。如果未能这样做会导致连接保持打开状态,很可能最终导致资源泄漏。
流式请求
当使用 AsyncClient
实例发送流式请求体时,应该使用异步字节生成器而非普通字节生成器:
async def upload_bytes():
... # 生成字节内容
await client.post(url, content=upload_bytes())
显式传输实例
当直接实例化传输对象时,需要使用 httpx.AsyncHTTPTransport
。
例如:
>>> import httpx
>>> transport = httpx.AsyncHTTPTransport(retries=1)
>>> async with httpx.AsyncClient(transport=transport) as client:
>>> ...
支持的异步环境
HTTPX 支持使用 asyncio
或 trio
作为异步环境。
它会自动检测使用哪一个作为套接字操作和并发原语的后端。
AsyncIO
AsyncIO 是 Python 的 内置库,用于通过 async/await 语法编写并发代码。
import asyncio
import httpx
async def main():
async with httpx.AsyncClient() as client:
response = await client.get('https://www.example.com/')
print(response)
asyncio.run(main())
Trio
Trio 是 一个替代的异步库,基于 结构化并发原则 设计。
import httpx
import trio
async def main():
async with httpx.AsyncClient() as client:
response = await client.get('https://www.example.com/')
print(response)
trio.run(main)
Important
必须安装 trio
包才能使用 Trio 后端。
AnyIO
AnyIO 是一个基于 asyncio
或 trio
的异步网络与并发库。它能与你所选后端(默认为 asyncio
)的原生库无缝集成。
import httpx
import anyio
async def main():
async with httpx.AsyncClient() as client:
response = await client.get('https://www.example.com/')
print(response)
anyio.run(main, backend='trio')
调用 Python Web 应用
关于直接调用 ASGI 应用的详细信息,请参阅ASGITransport
文档。