FastAPI 零基础入门完整教程(上)

FastAPI 零基础入门完整教程(上)

前言

本文带你从零上手 FastAPI,适合掌握基础Python语法、想要快速搭建后端接口的开发者。
读完本文你可以:搭建Web接口、接收各类请求参数、使用自动交互式接口文档、理解FastAPI高性能的底层原理。

前置要求:掌握基础 Python 语法,会使用 pip 安装包。

📑 文章目录

一、基础概念

什么是 FastAPI

FastAPI 是一个基于 Python 的高性能 Web 框架,专门用于快速构建 API 接口服务。
底层依托两大核心库:

  • Pydantic:负责数据类型校验、参数解析
  • Starlette:高性能异步 Web 底层框架

FastAPI 两大核心亮点

  1. Pydantic 类型提示与自动验证
    依靠类型注解定义数据格式,自动校验前端传入参数,不用手写大量if判断校验逻辑,代码更简洁。
from pydantic import BaseModel

class User(BaseModel):
    username: str
    password: str

@app.post("/register")
async def register(user: User):
    return user
  1. 自动生成交互式文档
    框架内置接口文档页面,启动服务后直接访问,浏览器内就能调试测试接口,不用额外借助Postman。
    两个文档地址:
  • 交互式在线调试文档:http://127.0.0.1:8000/docs(Swagger UI,日常开发首选)
  • 简洁静态文档:http://127.0.0.1:8000/redoc

二、同步阻塞 VS 异步非阻塞(性能核心原理)

这是FastAPI高性能的关键,我们用两张流程图直观区分两种运行模式。

1. 传统同步框架(Flask 同步模式)

执行特点:串行排队
请求1遇到IO等待(查询数据库、网络请求)时,整个线程卡住。请求2、请求3只能原地等待,必须等请求1全部处理完成,才能开始处理下一个请求。
在这里插入图片描述

短板:IO密集场景资源浪费,并发能力弱。

2. FastAPI 异步模式(async/await)

执行特点:IO等待时切换任务
请求1进入IO等待阶段,不会占用线程。框架会立刻调度请求2开始执行;请求2遇到IO等待,继续调度请求3。
当某个请求的IO操作返回结果,再回头继续完成剩余逻辑。

优势:充分利用等待时间,IO密集场景并发能力大幅提升,性能接近Go、Node.js。
在这里插入图片描述

⚠️ 重要提醒:
FastAPI同时兼容同步函数与异步函数。同步函数会放入线程池运行;想要发挥异步性能,数据库、Redis、网络请求需要使用异步客户端

三、环境准备:虚拟环境 + 依赖安装

3.1 为什么要创建Python虚拟环境

  1. 依赖版本隔离:不同项目可能需要同一个包的不同版本,全局环境会产生版本冲突;
  2. 环境干净可控:项目仅安装当前业务需要的库,不会混杂全局其他项目的依赖;
  3. 方便项目迁移部署:可以导出依赖清单 requirements.txt,其他电脑一键复现环境;
  4. 不污染系统Python:避免误修改系统自带Python的包,防止系统工具异常。

3.2 创建并激活虚拟环境

# 1. 创建虚拟环境,文件夹名称 venv(约定俗成命名)
python -m venv venv

激活命令:

# Windows cmd
venv\Scripts\activate
# Windows PowerShell
venv\Scripts\Activate.ps1
# Mac / Linux
source venv/bin/activate

激活成功后终端前缀会出现 (venv) 标识。

退出虚拟环境命令:deactivate

3.3 安装项目依赖

虚拟环境激活状态下执行:

pip install fastapi uvicorn
  • fastapi:框架主体
  • uvicorn:ASGI 异步服务器,运行FastAPI程序

可选:导出依赖清单(后续部署使用)
pip freeze > requirements.txt

四、第一个 FastAPI 程序

4.1 路由基础概念

路由就是 URL 地址和处理函数之间的映射关系,它决定了当用户访问某个特定网址时,服务器应该执行哪段代码来返回结果。

FastAPI 的路由定义基于 Python 的装饰器模式

@app.get("/")
async def root():
    return {"message": "Hello World"}
  • app:FastAPI实例对象
  • @app.get("/"):路由装饰器
    • @:Python装饰器语法标识
    • .get():代表监听 HTTP GET 请求
    • "/":匹配的URL路径
  • async def root():路径匹配成功后执行的处理函数

4.2 完整示例代码(包含基础路由)

新建文件 main.py

# 导入FastAPI核心类
from fastapi import FastAPI

# 创建FastAPI应用实例,整个项目服务核心载体
app = FastAPI()

# 根路径GET接口
@app.get("/")
async def root():
    # FastAPI自动将Python字典序列化为JSON返回
    return {"message": "Hello World"}

4.3 逐行代码解析

  1. from fastapi import FastAPI
    从fastapi框架导入核心类FastAPI,用于创建Web服务应用。

  2. app = FastAPI()
    实例化app对象,所有路由、接口全部挂载在该实例上。

  3. @app.get("/")
    路由装饰器:监听 HTTP GET 请求。客户端访问根路径 / 时,自动执行下方函数。

拓展:@app.post()@app.put()@app.delete() 对应不同请求方式。

  1. async def root():
  • async:定义异步函数,适合数据库读写、网络请求等IO密集场景,FastAPI推荐写法。
  • return {"message": "Hello World"}
    FastAPI自动完成JSON序列化,无需手动转换。

4.4 启动服务

uvicorn main:app --reload

参数说明:

  • main:文件名 main.py
  • app:代码里 app = FastAPI() 的实例变量
  • --reload:热重载,修改代码自动重启(仅开发环境使用

启动成功后访问地址:

  1. 业务接口地址:http://127.0.0.1:8000
  2. ✅【重点】交互式调试文档:http://127.0.0.1:8000/docs
  3. 简洁静态文档:http://127.0.0.1:8000/redoc

五、接口参数详解

5.1 参数基础定义

参数就是客户端发送请求时附带的额外信息和指令。
参数的作用:让同一个接口能根据不同的输入,返回不同的输出,实现动态交互。

通俗理解:同一段接口逻辑,接收不同参数,返回不同数据。例如 /book 接口传入 book_id=2,服务器返回编号2的图书信息。

5.2 参数三大分类

FastAPI最常用的3类HTTP参数,适用场景区分:

参数类型位置典型写法核心用途常用请求方法
路径参数URL路径内部/book/{id}定位唯一资源GET
查询参数URL ? 之后/search?page=1筛选、分页、排序GET
请求体(Body)HTTP消息体JSON格式创建、提交大批量数据POST / PUT

5.3 路径参数(Path Parameter)

路径参数直接写在URL路径中,使用{变量名}标记。

from fastapi import FastAPI
app = FastAPI()

@app.get("/book/{book_id}")
async def get_book(book_id: int):
    # 自动校验:访问非数字会直接返回错误
    return {"图书编号": book_id, "书名": f"图书{book_id}"}

访问示例:http://127.0.0.1:8000/book/3
适用场景:查询单个、唯一确定的资源详情。

重点解析:book_id: int 类型注解

代码中的 book_id: int 分为两部分:

  1. book_id:参数名称,必须和路由 {book_id} 保持同名,用于接收URL路径捕获的值;
  2. : int:Python类型注解(Type Hint),这是FastAPI实现自动处理的核心。

它带来三大能力:

  • 自动类型转换:URL传递的内容永远是字符串,如"3",FastAPI自动转换成整数 3
  • 自动参数校验:访问 /book/abc,字符串无法转为int,框架直接拦截请求,返回标准422错误,不需要手写if判断
  • 自动生成接口文档:docs页面自动识别参数类型,生成规范的接口说明。

对比演示

# 不带类型注解:book_id 永远是字符串,无自动校验
async def get_book(book_id):
# 添加 :int 注解:自动转换 + 合法性校验
async def get_book(book_id: int)

支持基础类型:strintfloatbool,FastAPI均可自动解析校验。

进阶:使用 Path() 增加精细化校验

单纯的类型注解只能限制基础数据类型;Path() 可以给路径参数附加额外校验规则、文档描述信息
需要先从fastapi导入Path

基础示例:

from fastapi import FastAPI, Path

app = FastAPI()

@app.get("/book/{id}")
async def get_book(id: int = Path()):
    return {"id": id, "title": f"这是第{id}本书"}
Path() 常用参数一览表
Path 参数说明
...代表参数必填(路径参数默认必填)
gtgreater than,数值大于
gegreater or equal,数值大于等于
ltless than,数值小于
leless or equal,数值小于等于
description参数描述,自动展示在接口文档中
min_length字符串最小长度
max_length字符串最大长度
带约束实战示例
# 限制id必须是大于0的整数,并添加文档描述
@app.get("/book/{id}")
async def get_book(
    id: int = Path(gt=0, description="图书ID,必须大于0")
):
    return {"id": id, "title": f"这是第{id}本书"}

测试效果:

  • 访问 /book/5 → 正常返回;
  • 访问 /book/0 → 触发校验失败,框架自动返回错误;

字符串路径参数长度限制示例:

@app.get("/user/{username}")
async def get_user(
    username: str = Path(min_length=3, max_length=20, description="用户名,3~20个字符")
):
    return {"username": username}

💡 区分:
普通 book_id:int:仅基础类型转换;
book_id:int = Path(...)类型转换 + 自定义校验规则 + 文档注释,项目正式开发推荐使用。

5.4 查询参数(Query Parameter)

URL问号?后面 key=value 形式,多个参数用&分隔。

@app.get("/book/list")
async def list_books(page: int = 1, size: int = 10):
    """page、size带默认值,前端可以不传"""
    return {"页码": page, "每页条数": size}

访问示例:http://127.0.0.1:8000/book/list?page=2&size=20
适用场景:列表分页、条件筛选、排序。

默认值与必填参数区分

代码中 page: int = 1, size: int = 10=1=10 就是查询参数的默认值

  1. 前端不传参数时
    访问:http://127.0.0.1:8000/book/list
    FastAPI 使用默认值:page=1,size=10

  2. 前端传参数时
    访问:http://127.0.0.1:8000/book/list?page=3&size=20
    传入的值会覆盖默认值:page=3,size=20

两种参数定义模式
  • 可选参数(存在默认值)
    page: int = 1,客户端可以不传参数,自动启用默认值
  • 必填查询参数(无默认值)
async def list_books(page: int, size: int = 10):

page 没有默认值,代表必填;请求不带?page=xx,框架直接返回422校验错误。

进阶:使用 Query() 增加精细化校验

普通默认值写法仅支持基础类型;Query() 可以给查询参数附加范围校验、字符串长度限制、接口文档描述,和路径参数的Path()配套对应。
需要先从fastapi导入Query

基础规范示例:

from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/book/list")
async def list_books(
    page: int = Query(1, ge=1, description="页码,最小为1"),
    size: int = Query(10, ge=1, le=100, description="每页条数,范围1~100")
):
    return {"页码": page, "每页条数": size}

字符串查询参数长度限制示例:

@app.get("/book/search")
async def search_book(
    keyword: str | None = Query(None, min_length=2, max_length=30, description="图书搜索关键词,选填")
):
    return {"关键词": keyword}

必填查询参数使用Query(...)写法(...代表必填):

@app.get("/book/filter")
async def filter_book(
    category: str = Query(..., description="图书分类,必填参数")
):
    return {"分类": category}

💡 统一记忆规律:
路径参数精细化校验 → Path()
查询参数精细化校验 → Query()
请求体参数校验 → Field()(来自pydantic)

5.5 请求体 Body(POST JSON参数)

5.5.1 请求体基础概念

在HTTP协议中,一次完整请求由三部分构成:

  1. 请求行:请求方法、URL、HTTP协议版本
  2. 请求头(Headers):元数据信息,例如Content-TypeAuthorization认证头
  3. 请求体(Body/消息体):真正承载业务数据的载体

请求体特点:

  • 位置:HTTP请求消息体内部
  • 适用场景:创建资源、更新资源,适合传递大量结构化数据(最常用JSON)
  • 常用请求方法:POSTPUT

⚠️ HTTP规范:GET请求不推荐携带请求体,所有查询筛选数据尽量放在查询参数。

5.5.2 CURL 请求示例解析
curl -X 'POST' \
  'http://127.0.0.1:8000/register' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
"username": "daqiu",
"password": "123456"
}'

参数拆解:

  • -X 'POST':指定HTTP请求方式为POST
  • 地址:目标接口URL
  • -H:添加请求头
    • Content-Type: application/json 关键:告诉后端本次请求体是JSON格式
    • accept: application/json:告知服务器,客户端期望接收JSON格式响应
  • -d(data):后面跟随的内容就是请求体JSON数据
5.5.3 为什么请求体必须使用 Pydantic BaseModel?
  1. 自动JSON解析与类型转换
    前端传递JSON字符串,FastAPI自动把JSON映射为BaseModel实例,无需手动json.loads()解析。
  2. 全自动数据校验
    自动校验字段类型、长度、数值范围;格式错误直接返回标准422错误,不用手写大量if判断。
  3. 自动生成接口文档
    docs页面自动识别模型字段、描述、约束,生成请求体示例。
  4. 代码可读性强
    集中定义数据结构,复用模型(新增、修改接口可以共用同一个实体类)。
  5. 内置序列化能力
    可以直接将模型对象返回,FastAPI自动序列化为JSON。

补充区分:路径/查询参数直接写在函数参数;请求体JSON数据必须用BaseModel接收,这是FastAPI设计规范。

5.5.4 基础请求体示例
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

# 定义接收JSON的模型
class BookCreate(BaseModel):
    title: str
    price: float
    author: str | None = None # 可选字段

@app.post("/book")
async def create_book(book: BookCreate):
    return {"msg": "图书创建成功", "data": book}

前端请求JSON示例

{
    "title": "FastAPI入门教程",
    "price": 59.9
}
5.5.5 进阶:Pydantic Field() 精细化校验

Path()Query()用于URL参数;请求体模型内部字段约束使用 Field(),需要从pydantic导入。

from pydantic import BaseModel, Field

class User(BaseModel):
    # ... 代表必填字段
    username: str = Field(..., min_length=3, max_length=20, description="用户名,3~20字符")
    password: str = Field(..., min_length=6, max_length=32, description="密码,最少6位")
    # 设置默认值,可选字段
    age: int = Field(default=18, ge=0, le=120, description="年龄,0~120,默认18岁")
Field() 常用参数对照表
Field 参数含义
...字段必填,没有默认值
default设置字段默认值
gt / ge数值大于 / 大于等于
lt / le数值小于 / 小于等于
min_length / max_length字符串最小/最大长度
description字段说明,自动展示在接口文档

完整可运行接口示例:

from fastapi import FastAPI
from pydantic import BaseModel, Field

app = FastAPI()

class UserRegister(BaseModel):
    username: str = Field(..., min_length=3, max_length=20, description="注册用户名,3~20位字符")
    password: str = Field(..., min_length=6, description="登录密码,至少6位")
    age: int | None = Field(None, ge=1, le=150, description="年龄,选填,范围1~150")

@app.post("/register")
async def register(user: UserRegister):
    return {"message": "注册成功", "user_data": user}

5.6 响应类型(Response)

5.6.1 基础原理

默认情况下,FastAPI 会自动将路径函数返回的 Python 对象(字典、列表、Pydantic模型),通过内置编码器转为JSON格式,自动包装成 JSONResponse 返回。

@app.get("/")
async def root():
    # 直接返回字典,FastAPI自动序列化为JSON
    return {"message": "hello world"}

优势:不需要手动调用 json.dumps(),开发者专注业务逻辑。

当需要返回 非JSON数据(HTML页面、纯文本、文件、数据流、跳转链接)时,就需要手动导入并使用各类响应类。

5.6.2 全部响应类型对照表

响应类型用途
JSONResponse默认响应,前后端分离接口标准,返回JSON数据
HTMLResponse返回HTML页面内容,用于服务端渲染网页
PlainTextResponse返回纯文本字符串
FileResponse返回本地文件,触发浏览器下载/预览
StreamingResponse流式输出(大文件分片、AI对话实时打字效果)
RedirectResponse请求重定向,跳转到另一个URL

导入方式:所有响应对象统一从 fastapi.responses 导入

from fastapi.responses import (
    JSONResponse,
    HTMLResponse,
    PlainTextResponse,
    FileResponse,
    StreamingResponse,
    RedirectResponse
)

5.6.3 响应类型两种设置方式

FastAPI 提供两种写法实现自定义响应,适用场景明确区分:

方式1:装饰器指定 response_class

适用场景:接口固定只返回同一种类型(HTML、纯文本),写法简洁,直接返回原始字符串,无需手动实例化响应对象。

@app.get("/html", response_class=HTMLResponse)
async def get_html():
    # 直接返回字符串,FastAPI自动包装为HTMLResponse
    return "<h1>这是标题</h1>"

✅ 优点:代码简洁,自动填充对应Content-Type
⚠️ 限制:接口只能使用单一响应类型,无法动态切换返回对象

方式2:函数内部 return 响应对象

适用场景:文件下载、图片、流式响应、需要动态切换响应类型、自定义文件名/响应头的场景

@app.get("/file")
async def get_file():
    file_path = "./files/1.jpeg"
    # 手动实例响应对象并返回
    return FileResponse(file_path)

✅ 优点:高度灵活,支持分支逻辑动态返回不同响应、传入专属参数(下载文件名、缓存策略等)

⚠️ 优先级规则:
如果同时配置 response_class 并且函数返回响应对象,以return的响应对象为准,装饰器参数失效

@app.get("/demo", response_class=HTMLResponse)
async def demo():
    # 最终返回文件,response_class配置不生效
    return FileResponse("test.jpg")

📌 最佳实践建议

  • 静态网页、纯文本接口 → 使用 response_class 装饰器写法
  • 文件下载、流式输出、重定向、动态多分支接口 → 直接return响应对象

5.6.4 response_model:自定义约束响应输出格式

核心概念

response_model 是路由装饰器(@app.get/@app.post)的关键参数,接收一个 Pydantic模型,用来严格约束API最终输出JSON结构
四大核心作用:

  1. 自动数据校验:过滤非法字段、校验数据类型;
  2. 自动序列化:数据库ORM对象、字典自动转为符合模型规范的JSON;
  3. 数据安全:自动剔除敏感字段(密码、密钥),防止隐私泄露;
  4. 自动生成接口文档/docs 页面展示标准返回结构。
完整示例代码
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

# 定义响应规范模型
class News(BaseModel):
    id: int
    title: str
    content: str

# 通过 response_model 指定输出格式
@app.get("/news/{id}", response_model=News)
async def get_news(id: int):
    # 返回原始字典,FastAPI自动按照News模型过滤、格式化输出
    return {
        "id": id,
        "title": f"这是第{id}本书",
        "content": "这是一本好书",
        "secret": "数据库内部密钥"  # 额外字段会被自动丢弃,不会返回前端
    }

重点特性:函数返回内容里超出模型定义的字段会被自动移除,天然防止敏感信息泄露。

拓展常用配置
  1. 返回列表数据:response_model=List[News]
from typing import List

@app.get("/news", response_model=List[News])
async def list_news():
    return [
        {"id":1,"title":"标题1","content":"内容1"},
        {"id":2,"title":"标题2","content":"内容2"}
    ]
  1. 可选参数、默认值、字段别名均可在Pydantic模型内定义,响应输出自动遵守规则。
🔔 区分易混淆概念
  • response_class:控制HTTP响应载体类型(JSON/HTML/文件/文本),修改 Content-Type
  • response_model只针对JSON响应,约束返回JSON里面有哪些字段、类型是什么,不改变响应载体。

可以同时使用:

@app.get("/news/{id}", response_model=News, response_class=JSONResponse)

5.6.5 HTTPException 异常响应处理

核心概念

对于客户端引发的业务错误(4xx状态码),例如资源不存在、认证失败、参数非法,推荐使用 fastapi.HTTPException,通过 raise 主动抛出异常,中断接口正常流程,返回标准格式错误响应。

适用场景:业务分支判断不满足条件,主动告知客户端请求错误。

完整可运行示例
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="当前id不存在")
    return {"id": id}

客户端访问 /news/100 收到响应:

{"detail":"当前id不存在"}
参数说明
  • status_code:HTTP标准状态码(404资源不存在、401未认证、403权限不足、400请求错误)
  • detail:给前端可读的错误信息
  • headers:可选,自定义异常响应头(常用于鉴权场景)
raise HTTPException(
    status_code=401,
    detail="token失效",
    headers={"WWW-Authenticate": "Bearer"}
)
⚠️ 重要区分
  1. raise HTTPException:主动抛出业务客户端错误(4xx);
  2. Python原生 Exception:服务端未知异常(500),框架默认捕获返回500;
  3. 不要使用 return JSONResponse 代替 HTTPException:异常可以被全局异常处理器统一捕获格式化。
拓展:结合response_model同时使用
@app.get("/news/{id}", response_model=News)
async def get_news(id: int):
    if id > 100:
        raise HTTPException(status_code=404, detail="新闻不存在")
    return {"id": id, "title":"标题","content":"内容"}

5.6.6 每种响应完整可运行示例

① JSONResponse(默认方式)

两种写法等价:

from fastapi import FastAPI
from fastapi.responses import JSONResponse
app = FastAPI()

# 写法1(推荐简写,自动封装JSONResponse)
@app.get("/json1")
async def json_demo1():
    return {"code": 200, "msg": "成功"}

# 写法2 手动构造JSONResponse(适合自定义状态码、响应头)
@app.get("/json2")
async def json_demo2():
    return JSONResponse(
        content={"code": 200, "msg": "手动JSON响应"},
        status_code=200
    )
② HTMLResponse 返回网页
@app.get("/html", response_class=HTMLResponse)
async def html_page():
    html_content = """
    <html>
        <head><title>测试页面</title></head>
        <body>
            <h1>Hello FastAPI HTML</h1>
        </body>
    </html>
    """
    return html_content
③ PlainTextResponse 纯文本
@app.get("/text", response_class=PlainTextResponse)
async def text_demo():
    return "这是一段纯文本内容,不是JSON"
④ RedirectResponse 重定向跳转
@app.get("/redirect")
async def redirect_demo():
    # 访问接口自动跳转到百度
    return RedirectResponse(url="https://www.baidu.com")
⑤ FileResponse 文件下载/预览
@app.get("/download")
async def download_file():
    # 参数填写本地文件路径
    return FileResponse(
        path="test.txt",
        filename="下载后的文件名.txt" # 浏览器下载显示的文件名
    )
⑥ StreamingResponse 流式响应(重点!AI问答常用)

适用于:超大文件分片传输、大模型打字机实时输出

import asyncio
from fastapi.responses import StreamingResponse

# 异步生成器,不断产生文本
async def stream_generator():
    words = ["你", "好", "!", "这", "是", "流", "式", "输", "出"]
    for w in words:
        yield w
        await asyncio.sleep(0.2)

@app.get("/stream")
async def stream_demo():
    return StreamingResponse(stream_generator(), media_type="text/plain")

5.6.7 补充关键知识点

知识点:自定义响应头、状态码

手动使用Response对象时,可以自由设置HTTP响应头:

@app.get("/header-demo")
async def header_test():
    return JSONResponse(
        content={"msg": "带自定义头部"},
        headers={"Token": "abc123456", "X-Name": "fastapi"}
    )

5.6.8 使用场景选择指南

  1. 前后端分离接口 → JSONResponse(默认)
    • 需要规范返回字段、屏蔽敏感信息 → 搭配 response_model
    • 客户端业务错误主动抛出 → HTTPException
  2. 需要返回网页页面 → HTMLResponse
  3. 返回简单文本、日志内容 → PlainTextResponse
  4. 文件下载、图片预览 → FileResponse
  5. AI流式对话、超大文件边读边传 → StreamingResponse
  6. 登录成功跳转、旧链接迁移 → RedirectResponse

5.6.9 常见误区

❌ 误区1:混用响应类型
不要同时返回 FileResponse 又返回字典,一次接口只能返回一个响应对象

❌ 误区2:GET请求试图返回大文件不用流式
超大文件直接使用FileResponse会一次性加载到内存,极限场景推荐StreamingResponse分片读取。

❌ 误区3:分不清 response_class 和 response_model
response_class 修改HTTP载体;response_model 约束JSON内部字段,仅对JSON响应生效。

❌ 误区4:以为response_model会修改入参
response_model只管控输出;请求入参校验使用 pydantic模型作为函数参数

❌ 误区5:混淆 HTTPException 和 return JSONResponse
客户端业务错误优先raise HTTPException,方便全局异常拦截统一格式化;不要手动return错误JSON。

六、同步函数 vs 异步 async

两种写法FastAPI都原生支持:

# 异步写法(推荐IO密集场景:数据库、网络请求)
@app.get("/async-demo")
async def async_demo():
    return {"type": "async"}

# 普通同步写法
@app.get("/sync-demo")
def sync_demo():
    return {"type": "sync"}

七、常用基础功能

1. 接口标签,文档分组

@app.get("/book/{book_id}", tags=["图书模块"])
async def get_book(book_id: int):
    return {"图书编号": book_id}

文档页面会按照标签分组,方便管理大量接口。

2. 自定义响应状态码

from fastapi import status

@app.post("/book", status_code=status.HTTP_201_CREATED)
async def create_book():
    return {"msg": "创建成功"}

八、常见踩坑记录

坑1:启动命令报错 Application object not found

原因:uvicorn 文件:实例名 名称不匹配
解决:确认 app = FastAPI() 的变量名和启动命令保持一致

坑2:POST接口参数放URL,不使用JSON请求体

现象:接口提示请求体缺失
解决:POST JSON参数需要在Body传递,不要放在查询参数

坑3:生产环境开启 --reload

风险:性能下降、存在安全隐患
解决:线上部署移除 --reload 参数

坑4:异步函数内部使用同步阻塞代码(time.sleep)

会阻塞事件循环,破坏异步并发能力;推荐使用asyncio.sleep()

坑5:路径参数忘记导入Path

报错提示找不到Path;解决:from fastapi import Path

坑6:查询参数精细化校验忘记导入Query

报错提示找不到Query;解决:from fastapi import Query

坑7:请求体内使用Path/Query,混淆三类校验函数

错误示范:模型字段内部写Query()
✅正确:请求体模型内部约束使用Field()

区分口诀:URL参数用Path/Query,模型内部字段约束用Field

坑8:混淆自动返回与手动Response

直接return字典会自动变成JSON;一旦手动构造HTMLResponse/FileResponse,就不能再返回字典。

坑9:FileResponse 文件路径错误

相对路径容易找不到文件,正式项目建议使用绝对路径。

坑10:StreamingResponse 忘记使用生成器

必须传入生成器函数(yield),直接传入完整字符串无法实现流式输出。

坑11:不清楚响应写法优先级

response_class 仅在函数返回原生字符串/字典时生效;如果return了响应实例,装饰器配置直接失效。

坑12:response_model 无法过滤外层自定义JSONResponse

如果手动 return JSONResponse(content=data),response_model 不会生效,需要直接返回原始数据交由框架序列化。

坑13:HTTPException 使用return而不是raise

必须使用 raise HTTPException(),return无法中断流程,不会触发标准异常处理。

坑14:HTTPException 无法被response_model格式化

response_model只处理正常成功返回;异常响应需要全局异常处理器统一封装。

九、小结

  1. FastAPI依靠类型注解 + Pydantic自动完成参数校验,减少重复代码;
  2. 内置交互式API文档,访问地址 http://127.0.0.1:8000/docs,极大提升前后端协作效率;
  3. 异步非阻塞机制让IO密集场景并发性能远超传统同步Web框架;
  4. 同步、异步写法同时兼容,开发使用uvicorn --reload,生产环境建议搭配进程管理工具;
  5. 开发项目优先创建独立虚拟环境,实现依赖隔离,避免版本冲突;
  6. 路由本质是URL与处理函数的映射关系,FastAPI通过装饰器语法快速定义路由。
  7. 参数分为路径参数、查询参数、请求体三类,不同场景选择合适的传参方式。
  8. 路径参数进阶:使用Path()可以实现数值范围、字符串长度等精细化自定义校验,同时完善接口文档。
  9. 查询参数进阶:使用Query()实现分页、筛选参数的约束校验,支持设置默认值、必填、长度限制、数值范围,自动同步到接口文档。
  10. 请求体进阶:POST/PUT传递JSON依靠BaseModel接收;模型字段约束使用Field();牢记区分:Path/Query处理URL参数,Field处理请求体模型字段。
  11. 响应支持多种载体(JSON/HTML/文件/流),区分response_classresponse_model;客户端业务错误优先抛出HTTPException

参考资料:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值