不整长篇大论,你也记不住,
FastAPI 的核心机制说白了就四件事:
- 装饰器绑定路径、
- 函数签名自动解析请求参数、
- Depends 注入服务端上下文、
- 函数体里写你自己的业务逻辑
这四块合起来,从前端发请求,到后端跑完逻辑返回结果,整个流程自动打通。
你写个 @app.post("/create")
,框架就知道这个路径归你管;函数签名里写 item_id: int
,如果 URL 里有 /create/{item_id}
,它就自动从路径里抠出来给你;写 q: str = None
,它就去查 query string;写个 Pydantic 模型当参数,它就去解析 body;写 token: str = Header(...)
,它就去读请求头。
这些字段函数像 Path()
、Query()
、Body()
,在基础场景下你可以不写,框架能猜出来;唯一你必须显式写的是 Header,因为 header 名和参数名经常对不上(比如 Authorization 对应 token),框架没法猜;只有当你想加点高级控制 ------ 比如改参数别名、加最小长度、写文档描述、控制 body 嵌套方式 ------ 才需要手动写这些字段函数。
Depends 是干啥的?它是框架给你提供的一个"预执行钩子" ------ 在真正跑你路由函数之前,先去执行你指定的函数,把结果塞进参数里;比如 user = Depends(get_current_user)
,框架会先跑 get_current_user()
,这个函数内部可能从 header 里拿 token、查数据库、返回用户对象,最后把 user 对象传给你;Depends 支持复用、支持替换、支持异步,特别方便测试的时候 Mock 掉真实逻辑。
函数体内部 完全你自己说了算:生成唯一 ID、获取当前时间、组装字典、调其他函数、处理异常、构造返回值 ,框架不插手,也不关心;所以这部分绝对不能写在函数签名里,因为它们不是"输入",是"执行过程"。 基于上面这套机制,参数和变量必须分成三层才好理解:
第一层:函数签名里直接声明的客户端参数
比如 item_id: int
、q: str = None
、token: str = Header(...)
------ 这些都是客户端必须传的,框架直接从 HTTP 请求里抠出来;Swagger 文档里显示的就是这些东西,前端调你接口,必须按这个来。
第二层:函数签名里用 Depends 注入、但底层依赖客户端输入的参数
比如 user = Depends(get_current_user)
------ 表面上你看不到客户端传啥,但其实 get_current_user
内部要读 token: str = Header(...)
,框架会把这个依赖"往上提",最终 Swagger 里还是会显示你需要传 Authorization;也就是说,这类参数本质还是客户端输入,只是被你包装了一层;客户端不知道 user 对象,但必须知道传 token ------ 如果你不分层,前端就会懵:到底要不要传 header?传哪个?文档里写不写?
第三层:纯后端资源 + 函数体内变量
比如 db = Depends(get_db)
------ 客户端完全不用管,框架自己从连接池给你捞一个连接;再比如 conversation_id = generate_unique_id()
------ 你自己在函数里生成的临时变量;这类东西,Swagger 里不显示,客户端不需要知道,也不应该知道;如果你把它们和前两类混在一起,文档就会乱写,测试就会乱 Mock,新人就会乱改 ------ 以为某个 header 是客户端要传的,结果其实是内部用的,一调就 400。
为什么非要分三层?因为影响面不一样!
第一层和第二层是因为必须客户端配合,文档必须写清楚,测试必须模拟请求; 而第三层是纯内部实现,文档不暴露,测试可以单元测,和 HTTP 无关; 你要是笼统说"前端参数"和"后端参数",那"后端参数"里哪些是客户端要参与的?哪些是纯内部的?根本分不清 ------ 写文档的人写错,调接口的人传错,写测试的人 Mock 错,改代码的人塞错位置 ------ 最后全乱套。而且这不是理论,这是 FastAPI 实打实的行为:
→ 第一层:框架直接从请求里拿原始数据;
→ 第二层:框架通过 Depends 调函数,函数再去请求里拿数据 ------ 本质上还是客户端输入;
→ 第三层:框架调函数或你自己写代码,完全不碰请求 ------ 纯后端;
读完之后如果还是很懵,没事,你再去看Fastapi的文档教程的时候,时不时想想今天看到的这些内容,很多时候就会恍然大悟,认真讲,3天学会FastAPI有点扯,1周搞透没啥问题。