从卡顿到丝滑:FastAPI 调用外部 API 的正确姿势(httpx 实战)

不难想像,问题有很大概率出在你随手 import 的那个 requests 身上。

先不急着看代码,一起把这件事从头捋一捋,了解下背后的原理,这样才能做到应对不同突发情况时,心里都有个谱。

🎯 本文能帮你解决什么

读完这篇,你基本上就知道了 FastAPI 里到底该用什么工具去访问其他的 API 拿数据,其实主要是学会怎么避开同步阻塞的大坑,还有就是 httpx 这个六边形战士怎么用、怎么配。也算一些经验的总结!

👩‍💻我是爱折腾的一名程序媛,喜欢研究全栈开发的各种实践,热爱分享踩坑后的收获与思考,也享受用代码写出各种实用小工具解决问题的快乐。

如果你也在技术这条路上向前走,关注我,愿我们能彼此陪伴,一起成为更好的自己 🌱

🗺️ 主要内容脉络

🔹 揪出让 FastAPI 变慢的真凶

🔹 三款常用 HTTP 客户端横评

🔹 httpx 安装与异步调用实战

🔹 那些一踩就炸的坑和最佳实践

🔹 总结与互动

🧱 第一部分:问题与背景------别让同步调用背刺你的并发

FastAPI 本身是基于 asyncio 的异步框架,像闪电一样快。但如果你在 async def 的异步接口函数里,直接调用 requests.get() 这种同步阻塞代码,那就相当于在高速公路的快车道上停了一辆拖拉机,那就只能中午出门了,因为早晚会出事。

requests 会把当前线程整个阻塞住,等待网络 IO 返回。而事件循环里的其他任务就全被卡在后面了,无法被调度。那了就没啥并发的事了,一秒回到解放前。

早期会使用一些小技巧:"用 asyncio.to_thread 把 requests 包起来不就行了?"

这确实能缓解,但那也只是贴个创可贴。线程切换是有开销的,而且当调用量一大起来,线程池本身又会成为瓶颈。结果就是治标不治本。

⚔️ 第二部分:工具横评------到底谁才是真命天子?

目前主流的在 FastAPI 里调用外部 API 的工具,就这三种:

🔹 requests:

同步老炮,接口简洁,生态完美。可惜,它不属于异步时代。

🔹 aiohttp:

纯异步,性能强悍。

但缺点也很扎眼------原生不支持 HTTP/2,API 的设计上偏底层,写起来代码量有点大,而且会话管理容易漏关

之前写代码时就出现过因为没关 ClientSession 结果导致文件描述符泄漏......

🔹 httpx:

新晋卷王,同时支持同步和异步,API 几乎是复刻 requests,上手零门槛。

而且原生支持 HTTP/1.1 和 HTTP/2,内置连接池,和 FastAPI 简直是天作之合。

说句主观的:

顺手的工具才是最好的!httpx 让我能用写 requests 的习惯,享受异步的红利,还要啥自行车?

你可能又会说,requests 早就被丢一边去了,还管它什么习惯?但它在咱们用 Python 写爬虫时,还是有大用的,异步是好,但不能解决所有问题!

🛠️ 第三部分:实战演示------装上 httpx,直接开干

安装上面还是老样子,包管理,一步搞定:

$ pip install httpx

但如果你需要 HTTP/2 支持,就把 httpx 换成 httpxhttp2 特定包就行。

接下来重点来了,怎么在 FastAPI 里写一个漂亮的异步调用呢?看代码:

from fastapi import FastAPI, Depends, Request

from contextlib import asynccontextmanager

import httpx

生命周期里全局定义一个异步客户端实例,用完记得关

@asynccontextmanager

async def httpx_lifespan(app: FastAPI):

复制代码
try:

    app.state.client = httpx.AsyncClient(

        base_url="https://api.example.com", timeout=10.0)

    logger.info(f"✅ Httpx客户端初始化完成!")

except Exception as e:

    logger.error(f"❌ Httpx客户端初始化失败: {e}")

    raise



yield



if hasattr(app.state, 'client'):

    await app.state.client.aclose()

    logger.info(f"✅ Httpx客户端已关闭!")

app = FastAPI(lifespan=httpx_lifespan)

核心:通过依赖函数获取客户端

async def get_http_client(request: Request) -> httpx.AsyncClient:

复制代码
return request.app.state.client

@app.get("/user/{user_id}")

async def get_user(user_id: int, client: httpx.AsyncClient = Depends(get_http_client)):

复制代码
resp = await client.get(f"/users/{user_id}")

resp.raise_for_status()  # 非200直接抛异常,好习惯

return resp.json()

看出来没?跟 requests 像得亲兄弟似的,只不过多了个 await。

利用 FastAPI 的 lifespan 生命周期管理,全局复用连接池,性能上也可以直接拉满。

这份代码你简单修改下里面的base_url基础链接,就可以用在你的项目上啦!

🚨 第四部分:注意事项与进阶思考------那些我踩过的坑

代码跑起来容易,但怎么让它跑得稳才是真本事。下面这些点,都是血的教训呀,最好了解下,心里有个数。

🔹 一定、一定、一定要设超时

默认情况下,httpx 的超时是 5 秒,但很多服务调用你等不了那么久。

更可怕的是,如果你忘了设,早期版本甚至默认无限等待,你在那刷半天,数据就是出不来,咋回事都不知道。

所以,在建客户端时,最好把 timeout=10.0 写得明明白白,这是保命符呀。

🔹 连接池耗尽比你想的常见

你可能会问:"我都异步了,怎么偶尔还卡?" 99% 是连接池满了。

httpx 默认连接池上限 100。如果下游接口响应慢,100 个连接全占着,新请求就只能干等。

最好的处理方式是,根据你的并发量,适当调大一下 limits 参数:

limits = httpx.Limits(max_connections=200, max_keepalive_connections=50)

client = httpx.AsyncClient(limits=limits)

🔹 别在响应里找不着北

正常我们获取返回数据,都是直接使用resp.json() ,但它是解析 JSON 的,如果下游返回 204 No Content,或者返回了个空 HTML,那这行就会炸掉。

最好的处理方式是,先判断 resp.status_code,或者用 resp.text 手动处理,稳一手。

如果你就就是想要 json ,最好也是加个 try/catch,能用json就json,不行咱就text

🔹 状态码的细节

resp.raise_for_status() 能在 4xx/5xx 时立刻抛异常,避免后续代码空转。这个习惯,建议刻在肌肉记忆里。它能帮你解决很多莫名其妙的问题!

🔹 再说个容易翻车的点

不建议在每个接口里临时 async with httpx.AsyncClient() as client: 去创实例。

每次都建连接、拆连接,TCP 握手开销巨大,那你的微服务可能秒变"假异步"了,虽然实际测试时,它内部维护了连接池,开销还好,但效果终究差点意思。

最好采用全局实例 + 事件管理,这个才是正道。

💬 做个总结

说到底,FastAPI 里的网络调用,核心就一句话:用异步客户端,全局管理,设好超时,看好连接池。

httpx 目前是我项目里的首选,不过技术没有银弹,如果你是追求极致吞吐量的场景,花点心思调教 aiohttp 也未尝不可,因为这个老将在能打方面还是胜过新兵的。

但大多数时候,httpx 的简洁与强大,已经完全足够的了。

这篇分享都是我在项目里一个Bug一个Bug改出来的经验总结,希望能帮你在写这类需求时少走点弯路。

相关推荐
weixin_4713830320 小时前
07 FastAPI
python·fastapi
Python私教1 天前
AI 生成到 90% 突然断了怎么办?我用 SSE、检查点和幂等把任务接着跑
fastapi
李昊哲小课2 天前
FastAPI + Echarts 构建可交互数据仪表板
信息可视化·echarts·fastapi
未知违规用户2 天前
大模型项目: 学习FastAPI 服务器开发
服务器·人工智能·python·学习·fastapi
普通网友3 天前
Python FastAPI 异步数据库管理
数据库·fastapi
观察员3 天前
深入理解 Pydantic 的 BaseModel
fastapi
郝同学今天有进步吗3 天前
构建 LangGraph Code Review Agent(七):实现规则匹配、Finding Guardrails 与 Markdown 报告
python·ai·fastapi·code review
智购科技自动售货机工厂3 天前
即时零售的风吹到自动售货机行业,会带来什么变化?~YH
大数据·人工智能·django·fastapi·零售·tornado
初圣魔门首席弟子3 天前
FastAPI 框架完全指南
fastapi
Jacky-0084 天前
FastAPI+PostgreSQL+SQLAlchemy2.0+asyncpg异步+alembic数据迁移==项目开发
fastapi