惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Engineering at Meta
Engineering at Meta
P
Privacy International News Feed
W
WeLiveSecurity
Spread Privacy
Spread Privacy
S
Schneier on Security
Google Online Security Blog
Google Online Security Blog
N
News and Events Feed by Topic
Forbes - Security
Forbes - Security
Cisco Talos Blog
Cisco Talos Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
L
Lohrmann on Cybersecurity
P
Privacy & Cybersecurity Law Blog
T
The Exploit Database - CXSecurity.com
C
CXSECURITY Database RSS Feed - CXSecurity.com
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
小众软件
小众软件
人人都是产品经理
人人都是产品经理
SecWiki News
SecWiki News
Schneier on Security
Schneier on Security
月光博客
月光博客
博客园_首页
腾讯CDC
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google DeepMind News
Google DeepMind News
Cyberwarzone
Cyberwarzone
www.infosecurity-magazine.com
www.infosecurity-magazine.com
AWS News Blog
AWS News Blog
WordPress大学
WordPress大学
AI
AI
酷 壳 – CoolShell
酷 壳 – CoolShell
Hacker News: Ask HN
Hacker News: Ask HN
Attack and Defense Labs
Attack and Defense Labs
IT之家
IT之家
P
Proofpoint News Feed
The Hacker News
The Hacker News
The Cloudflare Blog
Vercel News
Vercel News
Application and Cybersecurity Blog
Application and Cybersecurity Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Cloudbric
Cloudbric
C
Cisco Blogs
TaoSecurity Blog
TaoSecurity Blog
I
Intezer
Jina AI
Jina AI
雷峰网
雷峰网
阮一峰的网络日志
阮一峰的网络日志
Microsoft Azure Blog
Microsoft Azure Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
A
About on SuperTechFans
B
Blog

博客园 - 一名程序媛呀

Anki插件开发必知必会:钩子函数与右键菜单定制 httpx 传参总报错?这次把 GET、POST、文件上传到响应处理的坑给你一次填平 还在 XHR、Fetch 和 Axios 之间纠结?我踩过的坑,希望你一个都不用碰到 你的REST接口还在“过度投喂”数据吗?——FastAPI + GraphQL实战避坑指南 Uvicorn、Gunicorn 傻傻分不清?FastAPI 生产部署避坑指南 Termux里的二进制和脚本,到底怎么运行才不踩坑?Termux-service 保活妙招! 刚部署的 LibreTranslate 频频翻车?我掏出了 20 年前的 StarDict 词典,用 FastAPI 搭了个本地词典翻译 API 别再用网页翻译看源码了!你的私人翻译神器LibreTranslate,部署避坑指南来了 掏出手机就能搭个 WebDAV 同步服务器?这操作有点香 别只盯着GitBook了!这个文档神器让你的笔记秒变网站 写爬虫时用了代理还被封?Python 代理的那些隐藏坑,我替你踩明白了 FastAPI 身份验证总踩坑?这份 FastAPI Users “避坑指南”请收好 旧手机别扔!用 Termux 搭个私人云盘,比网盘香多了 你的FastAPI又在服务器上“跑不起来”了?来,今天咱把打包这件事彻底聊透 写页面时别再把 Element Plus 整个搬进来啦!Vue3按需加载的坑我帮你踩平了 前端包管理咋选?我从npm叛逃到pnpm的血泪史(附避坑指南) 聊聊 fetch 使用中我踩过的那些坑和正确打开方式 FastApiAdmin 后端接口开发好了,前端管理界面怎么调用与显示? 给 FastApiAdmin 加个“会议纪要”模块,我把后端二次开发的坑踩了个遍 我用了FastApiAdmin后,连夜把踩过的坑都整理出来了 告别 Typora 后的新欢:我把所有笔记迁移到了 Obsidian 这个“第二大脑” 你的Agent API还在裸奔?从认证到沙箱,我用FastAPI搭了几道防线 让 FastAPI Agent 思考不阻塞:手把手教你实现异步任务与后台处理方案 让FastAPI Agent真正记住你:聊聊会话记忆与持久化存储的落地实践 FastAPI Agent 函数调用实战:我让 AI 学会了“自己动手查天气“ 初探:用 FastAPI 搭建你的第一个 AI Agent 接口 FastAPI 少有人提的实用技巧:把 Depends 依赖提到路由层,代码少写60% FastAPI 生产环境静态文件完全指南:从 /favicon.ico 404 到 HSTS 混合内容,一次全根治 用了loguru我才明白,Python日志还能这么写 FastAPI 后台任务:BackgroundTasks 的使用场景与注意事项 FastAPI配置管理避坑指南:从硬编码到 .env 与 pydantic_settings 类,连路由用法都给你捋清楚 FastAPI 文件上传避坑全指南:分块存盘、类型校验与安全兜底 FastAPI + Pydantic 模型终极实战手册:从能跑就行到固若金汤,这些技巧你一定用得上 FastAPI + SQLAlchemy 2.0 通用CRUD操作手册 —— 从同步到异步,一次讲透 FastAPI订单防超卖实战:从数据库锁到Saga分布式事务,这一篇给你理清了 FastAPI 生产环境避坑指南:用 Alembic 管理数据库迁移,别再手动改表结构了! FastAPI服务半夜又挂了?先别急着重启,查查你的数据库连接池“池子”是不是漏了 FastAPI数据库ORM怎么选?我肝了三个Demo后,终于不再纠结了 Vue 3 组件通信,别只会用 Props 和 Emits 了,这几个狠活儿你得看看 Vue 3 组合式 API 香是香,但从Vue2迁移时你可别像我当初一样踩进这 3 个深坑里 我用fastapi-scaff搭了个项目,两天工期缩到两小时,老板以为我开挂了 FastAPI+Vue:文件分片上传+秒传+断点续传,这坑我帮你踩平了! FastAPI自动生成的API文档太丑?我花了一晚上把它改成了客户愿意付费的样子 告别手写 API 胶水代码:FastAPI 与 Vue 的“契约自动机” OpenAPI 实战 FastAPI + Vue 前后端分离实战:我的项目结构“避坑指南” FastAPI + Celery 实战:异步任务里调用 Redis 和数据库的全解析,及生产级组织方案 FastAPI里玩转Redis和数据库的正确姿势,别让异步任务把你坑哭了! FastAPI + Celery 实战:异步任务的坑与解法,我帮你踩了一遍 FastAPI子应用挂载:别再让root_path坑你一夜 FastAPI项目半夜报警吵醒你?聊聊告警这事儿怎么搞! 别再数据线了!用FastAPI 5分钟搭个局域网文件+剪贴板神器 FastAPI单元测试实战:别等上线被喷才后悔,TestClient用对了真香! FastAPI状态共享秘籍:别再让中间件、依赖和路由“各自为政”了! FastAPI实战:WebSocket vs Socket.IO,这回真给我整明白了! 从0到1,FastAPI + PostgreSQL + Tortoise ORM 实战避坑指南 FastAPI + PostgreSQL 实战:给应用装上“缓存”和“日志”翅膀 FastAPI + PostgreSQL 实战:从入门到不踩坑,一次讲透
从卡顿到丝滑:FastAPI 调用外部 API 的正确姿势(httpx 实战)
一名程序媛呀 · 2026-07-08 · via 博客园 - 一名程序媛呀

前段时间借助FastAPI搭建了一个本地词典API,用来翻译专业词汇和单词详细释意,但词典未收录的单词就没招了,于是又借助LibreTranslate实现了离线翻译,这下内容是都能出结果了,但两套API不在一个接口里,把它集成到PotKoodo Reader等使用时,还是不方便。

今天就借助httpx把他们集成在一起,让后台自动判断,本地词典找不到,那就从argos里拿,而不是我在外面一个搜索不到再开别一个窗口搜索。

📝 文章摘要
本文先简单说明下 requests、aiohttp 与 httpx 的优劣以及选择建议,然后使用 httpx 从安装到能写出异步客户端,同时分享下连接池耗尽、超时未设等实际开发中可能出现的踩坑经验。花点时间认真读完,这样以后你再写微服务调用时就会又快又稳,也不用再背锅。

🤔 你写的接口,到底慢在哪?

你可能也遇到过这种诡异场景:
本地跑得飞快的 FastAPI 服务,一上测试环境就卡得跟啥似的,CPU 还没跑满,请求就已经像是假期景点在排队等着上厕所一样。
结果你打开日志一看,好家伙,时间全耗在了调用那些下游 API 上。

不难想像,问题有很大概率出在你随手 import 的那个 requests 身上。
先不急着看代码,一起把这件事从头捋一捋,了解下背后的原理,这样才能做到应对不同突发情况时,心里都有个谱。

🎯 本文能帮你解决什么

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

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

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

🗺️ 主要内容脉络

🔹 揪出让 FastAPI 变慢的真凶

🔹 三款常用 HTTP 客户端横评

🔹 httpx 安装与异步调用实战

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

🔹 总结与互动

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

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

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

早期会使用一些小技巧:“用 asyncio.to_threadrequests 包起来不就行了?”
这确实能缓解,但那也只是贴个创可贴。线程切换是有开销的,而且当调用量一大起来,线程池本身又会成为瓶颈。结果就是治标不治本。

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

目前主流的在 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 换成 httpx[http2] 特定包就行。

接下来重点来了,怎么在 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改出来的经验总结,希望能帮你在写这类需求时少走点弯路。
如果你觉得对你有那么一...点点收获,那顺手点击收藏加个关注,以防下次用的时候划拉半天找不到在哪看过,也让我看到我的辛苦总结还是有用的,那我将甚感欣慰!
你还有什么踩坑经历或者不同意见,也欢迎评论区里聊聊,咱们一起学习,一起进步、成长!🎯