使用 httpx 发送同步与异步请求
约 1142 字大约 4 分钟
2026-05-10
httpx 是现代 Python HTTP 客户端,API 风格接近 requests,同时支持同步和异步请求、连接池、HTTP/2 等能力。
- 安装
- 同步请求
- Client
- 异步请求
- 1httpx 的同步 API 几乎和 requests 一样:迁移成本极低,先用 with httpx.Client() 替代 Session。
- 2异步:async with httpx.AsyncClient() as client: await client.get(url) —— 这是 httpx 真正的杀手锏。
- 3用 httpx.Client(base_url='...', headers=..., timeout=...) 一次配齐默认行为;不要每次写一遍。
- 4asyncio.gather + AsyncClient 跑大量 URL 时,永远配 asyncio.Semaphore 限流,否则容易被对方风控。
- 5Jupyter 已经有事件循环,await 写法略不同 —— 先在 .py 文件里练异步,理解 asyncio.run 后再回去。
httpx 是现代 Python HTTP 客户端,API 风格接近 requests,同时支持同步和异步请求、连接池、HTTP/2 等能力。
安装
pip install httpx同步请求
import httpx
response = httpx.get('https://httpbin.org/get', timeout=5)
print(response.status_code)
print(response.json())Client
多次请求同一服务时,应该使用 Client 复用连接。
import httpx
with httpx.Client(base_url='https://httpbin.org', timeout=5) as client:
response = client.get('/get', params={'page': 1})
print(response.json())异步请求
httpx.AsyncClient 可以和 asyncio 配合。
import asyncio
import httpx
async def main():
async with httpx.AsyncClient(timeout=5) as client:
response = await client.get('https://httpbin.org/get')
print(response.json())
asyncio.run(main())并发请求
import asyncio
import httpx
async def fetch(client, url):
response = await client.get(url)
response.raise_for_status()
return response.text
async def main():
urls = [
'https://httpbin.org/get?a=1',
'https://httpbin.org/get?a=2',
'https://httpbin.org/get?a=3',
]
async with httpx.AsyncClient(timeout=5) as client:
results = await asyncio.gather(*(fetch(client, url) for url in urls))
print(len(results))
asyncio.run(main())超时
client = httpx.Client(timeout=httpx.Timeout(10.0, connect=3.0))可以分别控制连接、读取、写入、连接池等待等超时。
HTTP/2
client = httpx.Client(http2=True)是否真正使用 HTTP/2 取决于服务端是否支持。
requests 还是 httpx
| 场景 | 推荐 |
|---|---|
| 简单同步脚本 | requests 或 httpx |
| 老项目、教程生态 | requests |
| 需要异步请求 | httpx |
| 需要同步/异步统一风格 | httpx |
| FastAPI 生态测试 | httpx |
为什么有了 requests 还要 httpx
如果你只是写简单脚本,requests 已经很好用。httpx 更适合这些情况:
- 项目已经使用
asyncio; - 需要同时请求很多接口;
- 想用一个库同时支持同步和异步写法;
- 需要更现代的超时、连接池、HTTP/2 支持。
初学者不用急着把所有代码都换成 httpx。建议先学会 requests,再在需要异步并发时学习 httpx。
同步 Client:适合普通脚本
import httpx
with httpx.Client(timeout=5) as client:
response = client.get('https://httpbin.org/get')
response.raise_for_status()
print(response.json())Client 会复用连接。对同一个网站连续请求多次时,比每次都新建请求更合适。
异步请求的运行方式
异步代码不能直接在普通函数里 await,需要放在 async def 里,再用 asyncio.run() 启动:
import asyncio
import httpx
async def main():
async with httpx.AsyncClient(timeout=5) as client:
response = await client.get('https://httpbin.org/get')
response.raise_for_status()
print(response.json())
asyncio.run(main())如果你在 Jupyter Notebook 里运行,可能已经有事件循环,写法会略有不同。初学阶段建议先在普通 .py 文件里练习。
并发请求时要控制数量
异步并发不是越多越好。一次性向同一个网站发几百个请求,可能导致自己机器卡住,也可能给对方服务造成压力。
可以用 asyncio.Semaphore 控制并发数量:
import asyncio
import httpx
urls = [f'https://httpbin.org/get?page={i}' for i in range(10)]
async def fetch(client, sem, url):
async with sem:
response = await client.get(url)
response.raise_for_status()
return response.json()
async def main():
sem = asyncio.Semaphore(3)
async with httpx.AsyncClient(timeout=5) as client:
tasks = [fetch(client, sem, url) for url in urls]
results = await asyncio.gather(*tasks)
print(len(results))
asyncio.run(main())这里最多同时执行 3 个请求。这个数字没有固定答案,要根据接口限制、网络情况和业务需求调整。
requests 和 httpx 的迁移对照
| requests | httpx 同步 | httpx 异步 |
|---|---|---|
requests.get(url) | httpx.get(url) | await client.get(url) |
requests.Session() | httpx.Client() | httpx.AsyncClient() |
response.status_code | 同名 | 同名 |
response.json() | 同名 | 同名 |
response.raise_for_status() | 同名 | 同名 |
API 很像,所以学会 requests 后,再学 httpx 不会太难。真正需要补的是 async/await 的执行模型。
总结
requests 简单稳定,httpx 更现代。需要 asyncio、高并发 HTTP 请求或统一同步/异步客户端时,httpx 是更合适的选择。
- 简单脚本用 requests 就够;需要 asyncio、并发请求或现代客户端能力时再考虑 httpx。
- `httpx.Client` 和 `AsyncClient` 都能复用连接,异步版本需要 `asyncio.run()` 启动。
- 并发请求要控制数量,不要把异步理解成无限制地同时发送请求。
版权所有
版权归属:Shuo Liu
