Skip to content

异步支持

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 支持使用 asynciotrio 作为异步环境。

它会自动检测使用哪一个作为套接字操作和并发原语的后端。

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 是一个基于 asynciotrio异步网络与并发库。它能与你所选后端(默认为 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文档