FastAPI基础程序、路由、请求与响应

一、FastAPI介绍

FastAPI

 

FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框架,专为在 Python 中构建 RESTful API 而设计。使用 Python 3.8+ 并基于标准的 Python 类型提示。建立在 Starlette 和 Pydantic 之上,利用类型提示进行数据处理,并自动生成API文档。于 2018 年 12 月 5 日发布第一版本,以其易用性、速度和稳健性在开发者中间迅速流行起来。支持异步编程,可在生产环境中运行。

FastAPI 特点

  • 高性能: 基于Starlette和Pydantic,利用异步(asynchronous)编程,提供出色的性能。
  • 自动文档生成: 自动生成交互式API文档,支持Swagger UI和ReDoc,让API的理解和测试更加直观。
  • 类型注解支持: 利用Python的类型提示,提供更严格的输入验证和更好的代码提示。
  • 异步支持: 支持异步请求处理,使得处理IO密集型任务更加高效。

FastAPI 适用场景

  • 构建API后端: 用于构建RESTful API,支持前后端分离的Web应用。
  • 微服务架构: 可以作为微服务的后端框架,支持快速开发和部署。
  • 数据处理API: 适用于处理数据,接收和返回JSON数据。
  • 实时通信: 支持WebSocket,适用于实时通信场景。

为什么选择 FastAPI?

  • Pythonic: 使用Python的自然语法和类型提示,降低学习曲线。
  • 性能优越: 利用异步编程和底层的Starlette框架,提供卓越的性能。
  • 文档友好: 自动生成交互式文档,减少文档维护的工作量。
  • 生态系统: 基于Python生态系统,可以方便地集成各种库和工具。

二、FastAPI 异步支持

FastAPI 的异步(asynchronous)特性是其高性能和高并发处理能力的核心之一。要理解 FastAPI 的异步,可以从以下几个方面入手:

2.1.什么是异步?

异步编程是一种编程范式,允许程序在等待某些操作(如 I/O 操作:数据库查询、文件读写、网络请求等)完成时,不阻塞主线程,而是去执行其他任务。当等待的操作完成后,再回来处理结果。
Python 中使用 async / await 语法来实现异步:
import asyncio

async def fetch_data():
    print("开始获取数据...")
    await asyncio.sleep(2)  # 模拟一个耗时的 I/O 操作
    print("数据获取完成!")
    return {"data": "some data"}

2.2.FastAPI 如何支持异步?

FastAPI 基于 Starlette(一个 ASGI 框架),完全支持异步。你可以在路由函数中直接使用 async def,FastAPI 会自动识别并以异步方式运行它。

同步 vs 异步路由示例:

from fastapi import FastAPI

app = FastAPI()

# 同步路由(阻塞)
@app.get("/sync")
def sync_route():
    time.sleep(2)  # 阻塞整个线程
    return {"message": "同步完成"}

# 异步路由(非阻塞)
@app.get("/async")
async def async_route():
    await asyncio.sleep(2)  # 不阻塞事件循环
    return {"message": "异步完成"}

2.3. 为什么异步能提高性能?

  • 在传统同步 Web 服务器(如 Flask + WSGI)中,每个请求通常由一个线程处理。如果该请求需要等待 I/O(比如查数据库),线程就“卡住”了,不能处理其他请求。
  • 而在异步模型(ASGI)中,一个事件循环可以同时管理成百上千个“协程”(coroutines)。当某个协程在等待 I/O 时,事件循环立即切换到其他协程继续工作。
  • 这使得 FastAPI 在高并发 I/O 密集型场景下(如 API 网关、微服务通信)性能远超传统同步框架。

同步:执行需要10s

image

@app.get("/sync")
def func_sync():
    start = time.time()
    for in range(10):
        time.slep(1)
    end = time.time()
    return {"time": f'{end-start:.2f}s'}

异步:执行只需要1s:

image

@app.get("/async")
async def func_async():
    start = time.time()
    task = [asyncio.slep(1) for in range(10)]
    awit asyncio.gather(*task)
    end = time.time()
    return {"time": f'{end-start:.2f}s'}

2.4.什么时候用异步?

✅ 适合使用异步的场景:
  • 调用外部 API(用 httpx.AsyncClient
  • 访问数据库(用 asyncpgdatabasesSQLAlchemy 1.4+ async
  • 文件读写(用 aiofiles
  • 任何 I/O 密集型任务
❌ 不适合异步的场景:
  • CPU 密集型任务(如图像处理、复杂计算)——此时异步无帮助,反而可能因上下文切换降低性能。这类任务应交给线程池或进程池(可用 loop.run_in_executor)。

2.5.混合使用同步与异步

FastAPI 允许你同时定义同步和异步路由。框架内部会自动处理:
  • 如果是 def(同步),FastAPI 会在线程池中运行它,避免阻塞事件循环。
  • 如果是 async def(异步),则直接在事件循环中运行。
所以即使你写同步代码,FastAPI 也能保证不会完全阻塞服务器(但性能不如原生异步)。

三、FastAPI 安装

使用 FastAPI 框架搭建 Web 服务

3.1.创建项目

  • 虚拟环境
conda create -n web_api_dev python=3.13

安装 FastAPI 很简单,这里我们使用 pip 命令来安装。

pip install fastapi

也可以使用以下命令直接安装 FastAPI 及所有可选依赖(推荐):

pip install "fastapi[all]"

这会安装:

  • fastapi - FastAPI 框架
  • uvicorn[standard] - ASGI 服务器
  • python-multipart - 表单和文件上传支持
  • jinja2 - 模板引擎
  • python-jose - JWT 令牌支持
  • passlib - 密码哈希
  • bcrypt - 密码加密
  • python-dotenv - 环境变量支持

这样我们就安装完成了。

  • FastAPI框架

image

3.2.运行项目

3.2.1.run 项目

  • 使用pycharm选择fastapi框架创建项目后,会默认创建main文件,生成示例代码如下,只需要在pycharm中点击运行按钮,即可运行项目

image

  • 运行后如下:

image

  • 浏览器访问跟路径:

image

  • 访问交互式文档:http://127.0.0.1:8000/docs

image

这时候是属于热部署,在启动后你直接修改代码,也可以看到内容:这里在helloword后面添加123,在浏览器访问

  • 先添加内容

image

  • 浏览器访问:

image

3.2.2.uvicorn

运行项目:

uvicorn main:app --reload

注意:

  • --reload:更改代码后自动重启服务器
  • main:指的需要运行的py文件名
  • app:指的是FastAPI实例对象名称

image

3.3.访问交互式文档

FastAPI 提供了内置的交互式 API 文档,使开发者能够轻松了解和测试 API 的各个端点。

这个文档是自动生成的,基于 OpenAPI 规范,支持 Swagger UI 和 ReDoc 两种交互式界面。

通过 FastAPI 的交互式 API 文档,开发者能够更轻松地理解和使用 API,提高开发效率

在运行 FastAPI 应用时,Uvicorn 同时启动了交互式 API 文档服务。

3.3.1. Swagger UI 风格

默认情况下,你可以通过访问 http://127.0.0.1:8000/docs 来打开 Swagger UI 风格的文档:

http://127.0.0.1:8000/docs

image

Swagger UI 提供了一个直观的用户界面,用于浏览 API 的各个端点、查看请求和响应的结构,并支持直接在文档中进行 API 请求测试。通过 Swagger UI,你可以轻松理解每个路由操作的输入参数、输出格式和请求示例。

3.3.2.ReDoc 风格的文档

通过 http://127.0.0.1:8000/redoc 来打开 ReDoc 风格的文档。

image

ReDoc 是另一种交互式文档界面,具有清晰简洁的外观。它使得开发者能够以可读性强的方式查看 API 的描述、请求和响应。与 Swagger UI 不同,ReDoc 的设计强调文档的可视化和用户体验。

四、FastAPI 基本路由

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

4.1.路由说明

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

image

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Hello World"}

代码说明:

  • FastAPI():创建 FastAPI 应用实例。
  • @app.get("/"):使用 @app.get 装饰器创建一个处理根路径的路由。
  • async def root():路由处理函数,返回一个包含 {"message": "hello world"} 的字典。

同一段接口逻辑,根据参数不同返回不同的数据

image

说明:

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

4.2.参数分类

在请求中参数分为:

  • 路径参数
  • 查询参数
  • 请求体

image

4.2.1.路径参数

路径参数说明

  • 位置:URL 路径的一部分 /book/{id}
  • 作用:指向唯一的、特定的资源
  • 方法:GET

image

输出:

image

路径参数 - 类型注解 Path

FastAPI 允许为参数声明额外的信息和校验,导入 FastAPI 的 Path 函数,Path 是一个用于为 路径参数(path parameters) 声明额外信息、元数据和校验规则的函数。它属于 FastAPI 的“依赖项”系统的一部分,与 QueryBodyHeader 等类似,但专门用于处理 URL 路径中的变量。

Path 支持的常用参数:

参数说明
default 默认值(路径参数不能有默认值,所以通常用 ...
alias OpenAPI 中显示的别名(较少用于路径参数)
title 参数标题(用于文档)
description 参数描述
gtge 大于、大于等于(数值)
ltle 小于、小于等于(数值)
min_lengthmax_length 字符串/列表最小/最大长度
regex(旧) / pattern(新) 正则表达式匹配
deprecated 标记为废弃

案例:添加两个方法,实现路由参数

from fastapi import FastAPI, Path

app = FastAPI()


@app.get("/book/{id}")
async def get_book(id: int = Path(..., ge=1, le=100, description="书籍id, 取值在1-100之间")):
    return {"id": id, "title": f"这是第{id}本书"}


@app.get("/author/{book_author}")
async def get_author_name(book_author: str = Path(min_length=2, max_length=20, description="书籍作者名")):
    return {"msg": f"这是{book_author}作者"}

打开接口文档:

image

4.2.2.查询参数

声明的参数不是路径参数时,路径操作函数会把该参数自动解释为查询参数(就是URL参数),

查询参数:

  • 位置:URL? 之后k1=v1&k2=v2
  • 作用:对资源集合进行过滤、排序、分页等操作
  • 方法:GET

示例:

image

调用执行:

image

查询参数 - 类型注解 Query

FastAPI Query() 函数完整参数详解表,如下:

参数名类型说明常用?适用类型备注
default 任意 默认值。若为 ...(Ellipsis),表示必需参数 ✅ 常用 所有 与 default_factory 互斥
default_factory Callable[[], Any] 用于动态生成默认值的函数(如 lambda: [] ⚠️ 较少用 所有 不能与 default 同时使用
alias str 字段别名(序列化/反序列化时使用的名称) ✅ 常用 所有 如 alias="user-name" → URL 中用 ?user-name=xxx
alias_priority int 别名优先级(控制 alias / validation_alias 等的生效顺序) ❌ 内部 所有 一般用户无需设置
validation_alias str | AliasPath | AliasChoices 仅用于输入验证的别名(Pydantic v2 新特性) ⚠️ 高级 所有 比 alias 更灵活
serialization_alias str 仅用于输出序列化的别名 ⚠️ 高级 所有 与 validation_alias 分离
title str OpenAPI 文档中的字段标题 ✅ 常用 所有 自动生成也可
description str OpenAPI 文档中的描述 ✅ 常用 所有 推荐写清楚
gt float 大于(>) ✅ 常用 数值 intfloatDecimal
ge float 大于等于(≥) ✅ 常用 数值  
lt float 小于(<) ✅ 常用 数值  
le float 小于等于(≤) ✅ 常用 数值  
min_length int 最小长度 ✅ 常用 strlisttuple 等  
max_length int 最大长度 ✅ 常用 同上  
pattern str 正则表达式(推荐使用 ✅ 常用 str Pydantic v2 标准方式
regex str 正则表达式(已弃用 ❌ 不推荐 str 未来版本会移除,用 pattern 替代
discriminator str 用于联合类型(Union)的字段区分(如多态) ⚠️ 高级 Union 类型 一般用于复杂模型
strict bool 是否启用严格模式(禁止类型转换) ⚠️ 调试用 所有 如 "123" → int 在非 strict 下允许
multiple_of float 必须是该值的整数倍 ⚠️ 特殊场景 数值 如 multiple_of=0.01 表示分单位
allow_inf_nan bool 是否允许 inf-infnan ⚠️ 特殊场景 float 默认 False
max_digits int Decimal 类型的最大位数(含小数) ⚠️ 金融场景 Decimal 需配合 decimal_places
decimal_places int Decimal 的小数位数 ⚠️ 金融场景 Decimal  
example Any 单个示例值(已弃用 ❌ 不推荐 所有 用 examples 或 openapi_examples
examples dict OpenAPI 示例(旧格式) ⚠️ 过渡 所有 结构较复杂
openapi_examples dict[str, Example] 推荐的 OpenAPI 示例格式(Pydantic v2 + FastAPI) ✅ 推荐 所有 支持多个命名示例
deprecated bool 是否标记为弃用 ✅ 常用 所有 Swagger UI 会显示删除线
include_in_schema bool 是否包含在 OpenAPI schema 中 ⚠️ 特殊需求 所有 设为 False 可隐藏参数
json_schema_extra dict | Callable 向 JSON Schema 添加额外字段 ⚠️ 高级 所有 用于扩展 OpenAPI
**extra Any 其他自定义元数据(不推荐) ❌ 避免 所有 Pydantic v2 

导入 FastAPI 的 Query 函数,使用案例:

from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/new/new_list")
async def get_new_list(
        skip: int = Query(0, ge=1, le=100, description="跳过的记录数"),
        limit: int = Query(10, ge=1, le=100, description="返回的记录数")
):
    return {"skip": skip, "limit": limit}

执行调用:

image

4.2.3.请求体

在HTP协议中,一个完整的请求由三部分组成:
① 请求行:包含方法、URL、协议版本
② 请求头:元数据信息(Content-Type、Authorization等)
③ 请求体:实际要发送的数据内容

请求体:

  1. 位置:HTP 请求的消息体(body)中;
  2. 作用:创建、更新资源携带大量数据,如:JSON;
  3. 方法:POST、PUT 等;

案例:

# 1.定义类型:需要继承BaseModel
class User(BaseModel):
    username: str
    password: str

# 2.添加类型注解
@app.post("/register")
async def register(user: User):
    """
    定义注册接口
    :param user:
    :return:
    """
    return user

输出:

image

请求体参数 - 类型注解 Field

Field 是 Pydantic(特别是 v2 版本)中用于定义模型字段元数据和验证规则的核心函数。它允许你为 Pydantic 模型(BaseModel)中的每个字段添加默认值、验证约束、文档说明、别名、示例等信息

Field 常用参数(与 FastAPI 的 Query/Body 共享)

参数说明示例
default 默认值 Field("guest")
default_factory 动态默认值(如 list Field(default_factory=list)
alias 外部使用的字段名(如 JSON key) Field(alias="user_id")
description 字段描述(用于文档) Field(description="用户邮箱")
gtgeltle 数值范围 Field(ge=1, le=100)
min_lengthmax_length 字符串/列表长度 Field(min_length=5)
pattern 正则匹配(字符串) Field(pattern=r"^\d{3}-\d{2}$")
examples / openapi_examples 示例值(OpenAPI) Field(examples=["test@example.com"])
deprecated 标记弃用 Field(deprecated=True)
json_schema_extra 扩展 JSON Schema Field(json_schema_extra={"unit": "years"})
from pydantic import BaseModel, Field

# 1.定义类型:需要继承BaseModel
class User(BaseModel):
    username: str = Field(min_length=8, max_length=20, description="用户名, 8~20个字符")
    password: str = Field(min_length=6, max_length=15, description="密码,6~15位")

五、FastAPI 请求和响应

在 FastAPI 中,请求(Request)和响应(Response)是与客户端交互的核心。FastAPI 提供了强大的工具来解析请求数据,并根据需要生成规范的响应。

1_CdUUublTxuAyIcnTFlxSUg

HTTP 的请求-响应模型通常由以下几个步骤组成:

  • 建立连接:客户端与服务器之间建立连接。在传统的 HTTP 中,这是基于 TCP/IP 协议的。最近的 HTTP/2 和 HTTP/3 则使用了更先进的传输层协议,例如基于 TCP 的二进制协议(HTTP/2)或基于 UDP 的 QUIC 协议(HTTP/3)。

  • 发送请求:客户端向服务器发送请求,请求中包含要访问的资源的 URL、请求方法(GET、POST、PUT、DELETE 等)、请求头(例如,Accept、User-Agent)以及可选的请求体(对于 POST 或 PUT 请求)。

  • 处理请求:服务器接收到请求后,根据请求中的信息找到相应的资源,执行相应的处理操作。这可能涉及从数据库中检索数据、生成动态内容或者简单地返回静态文件。

  • 发送响应:服务器将处理后的结果封装在响应中,并将其发送回客户端。响应包含状态码(用于指示请求的成功或失败)、响应头(例如,Content-Type、Content-Length)以及可选的响应体(例如,HTML 页面、图像数据)。

  • 关闭连接:在完成请求-响应周期后,客户端和服务器之间的连接可以被关闭,除非使用了持久连接(如 HTTP/1.1 中的 keep-alive)。

5.1.响应类型

默认情况下,FastAPI 会自动将路径操作函数返回的 Python 对象(字典、列表、Pydantic 模型等),经由 jsonable_ncoder 转换为JSON 兼容格式,并包装为 JSONResponse 返回。这省去了手动序列化的步骤,让开发者能更专注于业务逻辑。如果需要返回非 JSON 数据(如 HTML、文件流),FastAPI 提供了丰富的响应类型来返回不同数据

@app.get("/")
async def root():
    return {"message": "Hello World"}

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)

5.2.响应类型设置方式

  • 方式一:装饰器中指定响应类,场景:固定返回类型(HTML、纯文本等)
from fastapi import FastAPI
from starlette.responses import HTMLResponse

app = FastAPI()

@app.get("/html", response_class=HTMLResponse)
async def get_html():
    html = """
    <html>
        <body>
            <h1>这是HTML页面</h1>
        </body>
    </html>
    """
    return html
  • 方式二:返回响应对象,场景:文件下载、图片、流式响应
from fastapi import FastAPI
from starlette.responses import FileResponse

app = FastAPI()


@app.get("/file")
async def get_file():
    """
    返回文件
    :return:
    """
    file_path = "./static/fI5ntUNpK.png"
    return FileResponse(file_path)

FileRsponse 是 FastAPI 提供的专门用于高效返回文件内容(如图片、PDF、Excel、音视频等)的响应类。它能够智能处理文件路径、媒体类型推断、范围请求和缓存头部,是服务静态文件的推荐方式。

5.3.自定义响应数据格式

response_model 是路径操作装饰器(如 @app.get或 @app.post)的关键参数,它通过一个 Pydantic 模型来严格定义和约束 API 端点的输出格式。这一机制在提供自动数据验证和序列化的同时,更是保障数据安全性的第一道防线。

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class News(BaseModel):
    """
    新闻模型
    """
    id: int
    title: str
    content: str

@app.get("/news/{id}", response_model=News)
async def get_news(id: int):
    """
    获取新闻
    :param id:
    :return:
    """
    return {"id": id, "title": f"这是第{id}条新闻", "content": f"这是第{id}条新闻的内容"}

image

五、异常处理

对于客户端引发的错误(4x,如资源未找到、认证失败),应使用 fastapi.HTPException 来中断正常处理流程,并返回标准错误响应。

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

app = FastAPI()

class News(BaseModel):
    """
    新闻模型
    """
    id: int
    title: str
    content: str


@app.get("/news/{id}", response_model=News)
async def get_news(id: int):
    """
    获取新闻
    :param id:
    :return:
    """
    ids = [1, 2, 3, 4, 5]
    if id not in ids:
        # 404, 返回错误信息
        raise HTTPException(status_code=404, detail=f"当前{id}新闻不存在")
    return {"id": id, "title": f"这是第{id}条新闻", "content": f"这是第{id}条新闻的内容"}

image

posted @ 2026-01-19 11:38  酒剑仙*  阅读(12)  评论(0)    收藏  举报