FastApi学习笔记:一、FastAPI的基本使用
FastAPI
| 对比维度 | FastAPI | Flask | Django |
|---|---|---|---|
| 性能 | 高(异步支持) | 中 | 较低(同步) |
| 异步支持 | ✅ 内置 async/await | ❌ 需扩展 | ❌ 不原生 |
| 数据验证 | ✅ Pydantic 自动校验 | ❌ 手动处理 | ✅ ORM 级验证 |
| 自动文档 | ✅ 自动生成 | ❌ 需插件 | ❌ 需扩展 |
| 适用场景 | API、微服务、AI 推理 | 小型 Web 项目 | 大型网站 |
一、FastAPI基本使用
1. 创建项目
FastAPI → 存储位置及项目名称 → 创建虚拟环境 → Create

FastAPI框架虚拟环境运行项目有两种运行方式:
直接点击按钮运行和命令行运行
1.1 点击按钮运行(默认热重载)

1.2 命令行 run 项目
uvicorn main:app --reload

这是 FastAPI / Starlette 框架最常用的启动命令,作用是启动一个基于 Uvicorn 的 ASGI 服务器,运行你的 Python Web 应用。
把命令拆成三部分:
1.2.1 uvicorn
-
是什么:一个轻量、高性能的 Python ASGI 服务器
-
作用:专门用来运行 FastAPI、Starlette 这类现代异步 Web 框架
-
类比:相当于 Django/Flask 里的 runserver
1.2.2 main:app
-
格式固定:
模块名:应用实例 -
main→ 你的 Python 文件名main.py -
app→ 你在代码里创建的 FastAPI 实例(通常写app = FastAPI()) -
所以
main:app的意思是:去main.py文件里,找到名叫app的 FastAPI 应用并运行
1.2.3 --reload
-
作用:开发模式自动重载
-
效果:你修改代码后保存即生效,不用手动重启服务器(热重载)
-
注意:只在开发时用,生产环境不要加
uvicorn main:app --reload
使用 Uvicorn 服务器,启动
main.py里名为app的 FastAPI 应用,并开启代码自动重载功能。
接着修改代码 → 访问项目 → 访问路由 → 访问交互式文档
浏览器输入地址:http://127.0.0.1:8000/docs
2. 路由
路由可以帮助我们使用不同的路径访问到不同的结果。
路由就是 URL 地址和处理函数之间的映射关系,它决定了当用户访问某个特定网址时,服务器应该执行哪段代码来返回结果。
FastAPI 的路由定义基于 Python 的装饰器模式:
@app.get("/")
async def root():
return {"message": "hello world"}
from fastapi import FastAPI
# 创建FastAPI实例
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World 666"}
# @app.get("/hello/{name}")
# async def say_hello(name: str):
# return {"message": f"Hello {name}"}
# 访问/hello响应结果 msg:你好 FastAPI
@app.get("/hello")
async def get_hello():
return {"msg": "你好 FastAPI"}
然后再次访问接口文档,发现生成了 /hello 这个路径。
3. 参数
| 参数类型 | 位置 | 示例 | 作用 | 常用请求方法 |
|---|---|---|---|---|
| 路径参数 | URL 路径的一部分 | /book/{id} |
指向唯一、特定的资源 | GET |
| 查询参数 | URL 问号 ? 之后 |
k1=v1&k2=v2 |
对资源集合做过滤、排序、分页 | GET |
| 请求体 | HTTP 消息体 (body) 内 | JSON 格式数据 | 创建 / 更新资源,可携带大批量数据 | POST、PUT |
-
路径参数:资源标识,用来精准定位单个资源,例:
/book/12获取 id=12 的书籍 -
查询参数:筛选条件,例:
/book?page=1&size=10分页查书籍列表 -
请求体 Body:批量传参,GET 规范上不能携带请求体,新增/修改接口优先用 POST/PUT 提交 JSON
3.1 路径参数
-
位置:URL 路径的一部分,格式为
/资源/{参数名}(如/book/{id}) -
作用:指向唯一的、特定的资源(如获取某本具体书籍的信息)
-
常用方法:GET(用于获取资源)
id: int — Python 原生限定 id 为 int 类型:
@app.get("/book/{id}")
async def get_book(id: int):
return {"id": id, "title": f"这是第{id}本书"}
Path 函数
额外限制参数需求:可以导入 FastAPI 的 Path 函数来对请求参数进行限制:
@app.get("/book/{id}")
async def get_book(id: int = Path()):
return {"id": id, "title": f"这是第{id}本书"}
限定范围 1 到 100 之间:
# 定义请求的的路径,请求方式为get
@app.get("/book/{id}")
# 定义这个接口,接收一个参数id,数据类型为int
async def get_book(id: int=Path(...,gt=0,lt=101)):
# 返回响应结果
return {"id": id, "title": f"这是第{id}本书"}
| Path 参数 | 说明 |
|---|---|
... |
必填 |
gt / ge |
大于 / 大于等于 |
lt / le |
小于 / 小于等于 |
description |
描述 |
min_length / max_length |
长度限制 |
添加描述(description):
# 定义请求的的路径,请求方式为get
@app.get("/book/{id}")
# 定义这个接口,接收一个参数id,数据类型为int
async def get_book(id: int=Path(...,gt=0,lt=101,description="书籍id,取值范围为1-100")):
# 返回响应结果
return {"id": id, "title": f"这是第{id}本书"}
长度限制:
# 需求:查找书籍的作者,路径参数 name,长度范围 2-10
@app.get("/book/{name}")
async def get_name(name: str = Path(..., min_length=2, max_length=10, description="书籍名称,长度范围为2-10")):
return {"msg": f'这是{name}的信息'}
小结
-
路径参数出现在什么位置?URL 路径的一部分
-
如何为路径参数添加类型注解?Python 原生注解 和 Path 注解
练习
需求:定义两个接口,携带路径参数,并使用 Path 来实现类型注解,具体如下:
-
接口1:以新闻分类 id 为参数设计 URL,id 范围为 1 ~ 100
-
接口2:以新闻分类名称为参数设计 URL,分类名称长度为 2 ~ 10
from fastapi import FastAPI, Path
app = FastAPI()
# ---------------------------------------------------------
# 接口1:新闻分类 ID
# 需求:id 范围为 1 ~ 100
# URL 示例: /news/category/50
# ---------------------------------------------------------
@app.get("/news/category/{category_id}")
async def get_news_by_id(
category_id: int = Path(
...,
title="新闻分类ID",
description="新闻分类的唯一标识符",
ge=1, # 大于等于 1
le=100 # 小于等于 100
)
):
return {"category_id": category_id, "message": "成功获取该分类下的新闻"}
# ---------------------------------------------------------
# 接口2:新闻分类名称
# 需求:分类名称长度为 2 ~ 10
# URL 示例: /news/search/科技
# ---------------------------------------------------------
@app.get("/news/search/{category_name}")
async def get_news_by_name(
category_name: str = Path(
...,
title="新闻分类名称",
description="新闻分类的名称关键字",
min_length=2, # 最小长度 2
max_length=10 # 最大长度 10
)
):
return {"category_name": category_name, "message": "成功搜索该分类相关的新闻"}
3.2 查询参数
-
位置:URL 中
?之后,格式为key1=value1&key2=value2(如?page=1&sort=desc) -
作用:对资源集合进行过滤、排序、分页等操作(如查询"第1页、按时间降序"的书籍列表)
-
常用方法:GET(用于获取资源集合的筛选结果)
声明的参数不是路径参数时,路径操作函数会把该参数自动解释为查询参数。
在 news_list 后面拼接参数,如图:

# 需求:查询新闻页->分页,skip:跳过的记录数,limit:返回的记录数 10
@app.get("/news/news_list")
async def get_news_list(skip: int, limit: int = 10): #limit设置默认值为10
return {"skip": skip, "limit": limit}
Query 函数
导入 FastAPI 的 Query 函数:
# 需求:查询新闻页->分页,skip:跳过的记录数,limit:返回的记录数 10
@app.get("/news/news_list")
async def get_news_list(
skip: int = Query(0, description="跳过的记录数",lt=100),# 0的位置是设置默认值为0,如果是...则是必填
limit: int = Query(10, description="返回的记录数",lt=100)
):
return {"skip": skip, "limit": limit}
小结
-
查询参数出现在什么位置?URL
?之后,k1=v1&k2=v2 -
如何为查询参数添加类型注解?Python 原生注解 和 Query 注解
练习
需求:设计接口查询图书,要求携带两个查询参数:图书分类和价格
参数具体要求:
-
图书分类:默认值为
Python开发,长度限制 5 ~ 255 -
价格:限制大小范围 50 ~ 100
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/books/")
async def read_books(
# 需求:图书分类,默认值为 "Python开发",长度限制 5 ~ 255
category: str = Query(
"Python开发",
min_length=5,
max_length=255,
description="图书的分类名称"
),
# 需求:价格,限制大小范围 50 ~ 100
price: float = Query(
...,
ge=50,
le=100,
description="图书的价格范围"
)
):
return {
"category": category,
"price": price,
"message": "查询成功"
}
3.3 请求体参数
-
位置:HTTP 请求的消息体(body)中,常以 JSON 等格式携带数据
-
作用:用于创建、更新资源,或携带大量数据(如提交书籍的详细信息、更新用户资料)
-
常用方法:POST(创建资源)、PUT(更新资源)等
在 HTTP 协议中,一个完整的请求由三部分组成:
-
请求行:包含方法、URL、协议版本
-
请求头:元数据信息(Content-Type、Authorization等)
-
请求体:实际要发送的数据内容
定义接收类型:
from pydantic import BaseModel
class User(BaseModel):
username: str
password: str
意思就是:定义一个叫 User 的数据模型,它继承 BaseModel 的所有能力。
BaseModel是 Pydantic 库提供的一个"数据模板基类"。
自动数据校验:传错类型会直接报错,比如给
username传数字自动类型提示:PyCharm / VSCode 会自动提示字段,不会写错名
自动转 JSON / 字典:
user.dict() # 转字典 user.json() # 转 JSON 字符串FastAPI 专用请求:前端传 JSON,FastAPI 会自动解析并校验成
User对象
添加类型注解:
@app.post("/register")
async def register(user: User):
return user
响应结果如下:

需求:设计接口新增图书,图书信息包含:书名、作者、出版社、售价
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional
app = FastAPI()
# 1. 定义数据模型 (Pydantic Model)
class BookItem(BaseModel):
title: str # 书名
author: str # 作者
publisher: str # 出版社
price: float # 售价
# 2. 定义新增图书接口
@app.post("/books/", summary="新增图书")
async def create_book(book: BookItem):
"""
接收 JSON 格式的图书信息并返回
"""
# 这里通常会写数据库插入逻辑
return {
"message": "图书新增成功",
"book_info": book
}
Field 函数
类型注解 Field:导入 pydantic 的 Field 函数(上面的 Path 和 Query 函数都属于 FastAPI 的方法):
from pydantic import BaseModel, Field
class User(BaseModel):
username: str = Field(...)
password: str = Field(...)
# 注册:用户名和密码->str
class User(BaseModel):
username: str = Field(default="张三", min_length=2, max_length=10, description="用户名,长度范围为2-10")
password: str = Field(min_length=6, max_length=20, description="密码,长度范围为6-20")
@app.post("/register")
async def register(user: User):
return user
小结
-
请求体参数的作用是什么?创建、更新资源
-
如何定义、使用请求体参数?
# 注册:用户名和密码->str
class User(BaseModel):
username: str = Field(default="张三", min_length=2, max_length=10, description="用户名,长度范围为2-10")
password: str = Field(min_length=6, max_length=20, description="密码,长度范围为6-20")
@app.post("/register")
async def register(user: User):
return user
-
如何为请求体参数添加类型注解?Python 原生注解 和 Field 注解
练习
需求:设计接口新增图书,图书信息包含:书名、作者、出版社、售价
具体要求如下:
-
书名:不能为空;长度 2 ~ 20
-
作者:长度 2 ~ 10
-
出版社:默认值"黑马出版社"
-
售价:不能为空;价格大于0元
from fastapi import FastAPI
from pydantic import BaseModel, Field
from typing import Optional
app = FastAPI()
# 1. 定义数据模型
class Book(BaseModel):
# 书名:不能为空;长度 2 ~ 20
book_name: str = Field(
...,
min_length=2,
max_length=20,
description="书名,必填,2-20字"
)
# 作者:长度 2 ~ 10
author: str = Field(
...,
min_length=2,
max_length=10,
description="作者,必填,2-10字"
)
# 出版社:默认值"黑马出版社"
publisher: str = Field(
default="黑马出版社",
description="出版社,默认黑马出版社"
)
# 售价:不能为空;价格大于0元
price: float = Field(
...,
gt=0,
description="价格,必填,大于0"
)
# 2. 定义新增图书接口
@app.post("/books", summary="新增图书")
async def create_book(book: Book):
"""
接收图书信息,校验通过后返回
"""
# 这里可以添加保存到数据库的逻辑
return {"message": "图书新增成功", "book_data": book}
4. 响应类型
默认情况下,FastAPI 会自动将路径操作函数返回的 Python 对象(字典、列表、Pydantic 模型等),经由 jsonable_encoder 转换为 JSON 兼容格式,并包装为 JSONResponse 返回。这省去了手动序列化的步骤,让开发者能更专注于业务逻辑。
如果需要返回非 JSON 数据(如 HTML、文件流),FastAPI 提供了丰富的响应类型来返回不同数据。
| 响应类型 | 用途 | 示例 |
|---|---|---|
JSONResponse |
默认响应,返回 JSON 数据 | return {"key": "value"} |
HTMLResponse |
返回 HTML 内容 | return HTMLResponse(html_content) |
PlainTextResponse |
返回纯文本 | return PlainTextResponse("text") |
FileResponse |
返回文件下载 | return FileResponse(path) |
StreamingResponse |
流式响应 | 生成器函数返回数据 |
RedirectResponse |
重定向 | return RedirectResponse(url) |
FastAPI 响应类型设置方式:
| 设置方式 | 说明 | 适用场景 |
|---|---|---|
| 装饰器中指定响应类 | 在 @app.get() 等装饰器中,通过 response_class 参数声明 |
固定返回类型(如 HTML、纯文本) |
| 返回响应对象 | 在接口函数中直接 return 一个响应实例 | 文件下载、图片、流式响应 |
4.1 装饰器指定响应类(response_class)
这种方式会让 FastAPI 自动将返回的数据包装成指定类型的响应,适合固定类型的接口。
from fastapi import FastAPI
from fastapi.responses import HTMLResponse, PlainTextResponse
app = FastAPI()
# 方式1:装饰器中指定HTML响应
@app.get("/html", response_class=HTMLResponse)
async def get_html():
return "<h1>Hello, HTML!</h1>"
# 方式1:装饰器中指定纯文本响应
@app.get("/text", response_class=PlainTextResponse)
async def get_text():
return "Hello, Plain Text!"
4.2 直接返回响应对象
这种方式更灵活,可以直接控制响应的细节,适合文件、流等特殊场景。
FileResponse 是 FastAPI 提供的专门用于高效返回文件内容(如图片、PDF、Excel、音视频等)的响应类。它能够智能处理文件路径、媒体类型推断、范围请求和缓存头部,是服务静态文件的推荐方式。
from fastapi import FastAPI
from fastapi.responses import FileResponse, StreamingResponse
import io
app = FastAPI()
# 方式2:直接返回文件响应
@app.get("/download")
async def download_file():
return FileResponse("example.txt", filename="downloaded.txt")
# 方式2:直接返回流式响应
@app.get("/stream")
async def stream_data():
def generator():
yield b"Hello, "
yield b"Streaming!"
return StreamingResponse(generator(), media_type="text/plain")
装饰器指定(response_class):
-
优点:代码更简洁,自动序列化,文档自动识别
-
缺点:灵活性较低,无法精细控制响应头、文件路径等细节
直接返回响应对象:
-
优点:高度灵活,可直接设置响应头、状态码、媒体类型等
-
缺点:需要手动处理部分序列化逻辑,对文档自动识别的支持较弱
4.3 自定义响应数据格式
response_model 是路径操作装饰器(如 @app.get 或 @app.post)的关键参数,它通过一个 Pydantic 模型来严格定义 API 端点的输出格式。这一机制在提供自动数据验证和序列化的同时,更是保障数据安全性的第一道防线。
response_model 的核心功能包括:
-
强制输出格式:不管接口函数返回什么数据,最终给前端的响应都会被强制转换成
response_model指定的结构 -
自动数据验证:确保返回的数据完全符合 Pydantic 模型的类型、字段和校验规则
-
自动序列化:自动处理对象转 JSON,同时过滤掉模型中未定义的额外字段,防止敏感信息泄露
from pydantic import BaseModel
from fastapi import FastAPI
app = FastAPI()
# 需求: 新闻接口 → 响应数据格式 id、title、content
class News(BaseModel):
id: int
title: str
content: str
@app.get(path="/news/{id}", response_model=News)
async def get_news(id: int):
return {
"id": id,
"title": f"这是第{id}本书",
"content": "这是一本好书"
}
如果响应时缺失字段:
@app.get("/news/{id}", response_model=News)
async def get_news(id: int):
return {
"id": id,
"title": f"这是第{id}本书"
}
FastAPI 的 response_model 在校验时发现必填字段缺失,直接抛出 ResponseValidationError,前端会收到 500 Internal Server Error。
解决方法:
方法1:把模型字段设为可选(允许缺失)
修改 News 模型,给 content 字段加上默认值,让它变成非必填项:
from typing import Optional
class News(BaseModel):
id: int
title: str
content: Optional[str] = None # 允许缺失,默认返回 null
方法2:缺失字段不返回(用 response_model_exclude_unset)
在装饰器中加上 response_model_exclude_unset=True,接口没返回的字段,最终响应里就不会出现:
@app.get(
"/news/{id}",
response_model=News,
response_model_exclude_unset=True # 关键配置
)
async def get_news(id: int):
return {"id": id, "title": f"这是第{id}本书"}
此时前端收到的响应是:
{"id": 66, "title": "这是第66本书"}
不会出现 content 字段,也不会报错。
5. 异常处理
对于客户端引发的错误(4xx,如资源未找到、认证失败),应使用 fastapi.HTTPException 来中断正常处理流程,并返回标准错误响应。
# 需求: 按 id 查询新闻 → 1 - 6
from fastapi import FastAPI, HTTPException
app = FastAPI()
@app.get("/news/{id}")
async def get_news(id: int):
id_list = [1, 2, 3, 4, 5, 6]
if id not in id_list:
raise HTTPException(status_code=404, detail="您查找的新闻不存在")
return {"id": id}
HTTPException 的作用
这是 FastAPI 提供的标准异常类,专门用来抛出 HTTP 错误:
-
接收
status_code:设置响应状态码(如 404) -
接收
detail:设置错误详情信息,会自动返回给前端 -
抛出后会中断接口后续流程,直接返回标准错误响应
运行效果
-
当
id在[1-6]内时:正常返回{"id": id} -
当
id不在[1-6]内时:抛出 404 错误,前端收到:
{
"detail": "您查找的新闻不存在"
}
6. 中间件
中间件(Middleware)是一个在每次请求进入 FastAPI 应用时都会被执行的函数。
它在请求到达实际的路径操作(路由处理函数)之前运行,并且在响应返回给客户端之前再运行一次。
中间件的执行顺序是按代码自下而上开始执行(类似 Java 的 AOP)。
-
作用是什么? 为每个请求添加统一的处理逻辑(记录日志、身份认证、跨域、设置响应头、性能监控等)

中间件:函数的顶部使用装饰器 @app.middleware("http")
@app.middleware("http")
async def middleware1(request, call_next):
print("中间件1 start")
response = await call_next(request)
print("中间件1 end")
return response
from fastapi import FastAPI
app = FastAPI()
@app.middleware("http")
async def middleware1(request, call_next):
print("中间件1 start")
response = await call_next(request)
print("中间件1 end")
return response
@app.middleware("http")
async def middleware2(request, call_next):
print("中间件2 start")
response = await call_next(request)
print("中间件2 end")
return response
@app.get("/")
async def root():
return {"message": "Hello World"}
由以上程序运行的结果可以看出,中间件开始是自下而上的,而结束是自上而下。
中间件2 start
中间件1 start
接口运行
中间件1 end
中间件2 end
7. 依赖注入
依赖项:可重用的组件(函数/类),负责提供某种功能或数据。
注入:FastAPI 自动帮你调用依赖项,并将结果"注入"到路径操作函数中。
优点:
-
代码复用:一次编写,多处使用
-
解耦:业务逻辑与基础设施代码分离
-
易于测试:轻松地用模拟依赖替换真实依赖进行测试
步骤:创建依赖项 → 导入 Depends → 声明依赖项
from fastapi import FastAPI, Query
from fastapi.params import Depends
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
# 分页参数逻辑共用:新闻列表和用户列表
# 依赖项
async def common_parameters(
skip: int = Query(0, ge=0), # ✅ 自动获取查询参数
limit: int = Query(10, le=60)
):
return {"skip": skip, "limit": limit}
# 声明依赖项->依赖注入
@app.get("/news/news_list")
async def news_list(commons = Depends(common_parameters)):
return commons
@app.get("/user/user_list")
async def user_list(commons = Depends(common_parameters)):
return commons
依赖注入 Depends 的好处(Depends ≈ Spring 的 @Bean + @Autowired):
-
✅ 代码复用:不用重复写参数
-
✅ 统一校验:Query 校验只写一次
-
✅ 结构清晰:业务逻辑和公共逻辑分离
-
✅ 可替换、可测试
普通公共函数 = 自己手动调用(拿不到请求、Query、Header、Cookie;不能做自动参数校验;不能做依赖嵌套;不能自动注入数据库、token 等资源)
Depends = FastAPI 自动帮你调用 + 自动传请求参数 + 自动校验
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)