一、FastAPI
1、介绍
- FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框架,使用 Python 并基于标准的 Python 类型提示
- 关键特性:
- 快速:可与 NodeJS 和 Go 并肩的极高性能(归功于 Starlette 和 Pydantic)。最快的 Python web 框架之一
- 高效编码:提高功能开发速度约 200% 至 300%
- 更少 bug:减少约 40% 的人为(开发者)导致错误
- 智能:极佳的编辑器支持。处处皆可自动补全,减少调试时间
- 简单:设计的易于使用和学习,阅读文档的时间更短
- 简短:使代码重复最小化。通过不同的参数声明实现丰富功能。bug 更少
- 健壮:生产可用级别的代码。还有自动生成的交互式文档
- 标准化:基于(并完全兼容)API 的相关开放标准:OpenAPI (以前被称为 Swagger) 和 JSON Schema
2、安装
pip install fastapi "uvicorn[standard]" -i https://repo.huaweicloud.com/repository/pypi/simple/
3、入门案例
3.1 创建项目
- 直接 pycharm 创建,默认有一些代码
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
@app.get("/hello/{name}")
async def say_hello(name: str):
return {"message": f"Hello {name}"}
3.2 启动测试
- 启动方式一:命令启动
uvicorn main:app --reload
- 启动方式一:点击启动按钮
- 通过默认地址访问:【 http://127.0.0.1:8000/ 】

4、交互式 API 文档
- 现在访问【 http://127.0.0.1:8000/docs 】
- 你会看到自动生成的交互式 API 文档(由 Swagger UI 生成):

5、类型提示
- 这些"类型提示"是一种新的语法(在 Python 3.6 版本加入)用来声明一个变量的类型。通过声明变量的类型,编辑器和一些工具能给你提供更好的支持
- 比如:原来我们定义一个函数方式如下
def get_full_name(first_name, last_name):
full_name = first_name.title() + " " + last_name.title()
return full_name
print(get_full_name("john", "doe"))
- 现在定义一个函数方式如下
def get_full_name(first_name: str, last_name: str):
full_name = first_name.title() + " " + last_name.title()
return full_name
print(get_full_name("john", "doe"))
- 不只是
str类型,你能够声明所有的标准 Python 类型。比如以下普通类型intfloatboolbytes
def get_items(item_a: str, item_b: int, item_c: float, item_d: bool, item_e: bytes):
return item_a, item_b, item_c, item_d, item_d, item_e
- 嵌套类型:有些容器数据结构可以包含其他的值,比如
dict、list、set和tuple。它们内部的值也会拥有自己的类型,你可以使用 Python 的typing标准库来声明这些类型以及子类型,它专门用来支持这些类型提示
# 列表
from typing import List
def process_items(items: List[str]):
for item in items:
print(item)
# 元组和集合
from typing import Set, Tuple
def process_items(items_t: Tuple[int, int, str], items_s: Set[bytes]):
return items_t, items_s
# 字典
from typing import Dict
def process_items(prices: Dict[str, float]):
for item_name, item_price in prices.items():
print(item_name)
print(item_price)
# 类
class Person:
def __init__(self, name: str):
self.name = name
def get_person_name(one_person: Person):
return one_person.name
- 总结:就是给函数的形式参数一个类型说明,方便调用的时候基于提示
6、Pydantic 模型
- Pydantic 是一个用来执行数据校验的 Python 库
- 你可以将数据的"结构"声明为具有属性的类。每个属性都拥有类型。接着你用一些值来创建这个类的实例,这些值会被校验,并被转换为适当的类型(在需要的情况下),返回一个包含所有数据的对象。然后,你将获得这个对象的所有编辑器支持
- 基本使用案例
from datetime import datetime
from pydantic import BaseModel
class User(BaseModel):
id: int
name: str = "John Doe"
signup_ts: datetime | None = None
friends: list[int] = []
external_data = {
"id": "123",
"signup_ts": "2017-06-01 12:22",
"friends": [1, "2", b"3"],
}
user = User(**external_data)
print(user)
# > User id=123 name='John Doe' signup_ts=datetime.datetime(2017, 6, 1, 12, 22) friends=[1, 2, 3]
print(user.id)
# > 123
7、读取环境变量
-
对于有的资源,我们可能需要保护其隐私(比如注册阿里千问模型后的 API KEY),那么在代码中我们就不应该把它暴露出来
-
这种情况下,我们可以把其放在计算机的系统变量中,然后通过这个变量的名字去访问它,步骤如下
- 第一步:在系统变量下面,创建一个系统变量,值就是对应的内容
![image-20251017091642161]()
- 第二步:打开一个新的 cmd,测试配置是否成功
![image-20251017091836705]()
- 第三步:代码中读取系统变量
import os name = os.getenv("DASHSCOPE_API_KEY") print(name)
8、并发 async / awai
async/await是 FastAPI 的核心机制之一,它让 FastAPI 能够高性能地处理并发请求。我们来系统地讲清楚它的原理、用法和在 FastAPI 中的意义- Python 默认是同步执行的,也就是一行代码执行完再执行下一行,比如下面这个代码,如果有 100 个请求在等待网络响应,程序就会阻塞,CPU 其实是空闲的
def get_data():
data = request_api() # 等待网络返回
return data
8.1 是什么
async用来定义异步函数(协程)await用来等待一个异步操作完成(非阻塞)
换句话说:
async表示“我可以异步执行”await表示“我现在要等待这个异步操作,但不会阻塞别人”
8.2 为什么用
- FastAPI 基于 ASGI(Asynchronous Server Gateway Interface)
- 支持异步请求处理
- 能同时处理成千上万的并发请求
8.3 案例助解
- 通过一个同步和异步案例输出结果,来助力理解
- 安装
requests和httpx库
pip install -i https://repo.huaweicloud.com/repository/pypi/simple/ requests httpx
8.3.1 同步案例
- 案例代码
import time
import requests
def fetch(url):
print(f"开始请求:{url}")
resp = requests.get(url)
print(f"结束请求:{url}")
return resp.status_code
def main():
start = time.time()
urls = [
"https://httpbin.org/delay/1",
"https://httpbin.org/delay/1",
"https://httpbin.org/delay/1",
]
for url in urls:
fetch(url)
print("总耗时:", time.time() - start)
if __name__ == "__main__":
main()
- 输出结果
开始请求:https://httpbin.org/delay/1
结束请求:https://httpbin.org/delay/1
开始请求:https://httpbin.org/delay/1
结束请求:https://httpbin.org/delay/1
开始请求:https://httpbin.org/delay/1
结束请求:https://httpbin.org/delay/1
总耗时: 14.537713527679443
8.3.2 异步案例
- 案例代码
async def:声明函数为异步async with:异步上下文(非阻塞方式创建 client)await client.get():等待网络返回,但不会卡住事件循环response.json():拿到返回数据
import asyncio
import time
import httpx
async def fetch(url):
print(f"开始请求:{url}")
async with httpx.AsyncClient() as client:
resp = await client.get(url)
print(f"结束请求:{url}")
return resp.status_code
async def main():
start = time.time()
urls = [
"https://httpbin.org/delay/1",
"https://httpbin.org/delay/1",
"https://httpbin.org/delay/1",
]
tasks = [fetch(url) for url in urls]
await asyncio.gather(*tasks)
print("总耗时:", time.time() - start)
if __name__ == "__main__":
asyncio.run(main())
- 输出结果
开始请求:https://httpbin.org/delay/1
开始请求:https://httpbin.org/delay/1
开始请求:https://httpbin.org/delay/1
结束请求:https://httpbin.org/delay/1
结束请求:https://httpbin.org/delay/1
结束请求:https://httpbin.org/delay/1
总耗时: 3.7947113513946533
8.4 总结对比
| 特性 | 同步版本 | 异步版本 |
|---|---|---|
| 写法 | def |
async def |
| 调用 | 顺序执行 | 并发执行 |
| 等待IO | 阻塞线程 | 非阻塞 |
| 执行时间 | 约 14.5 秒 | 约 3.8 秒 |
| 使用库 | requests |
httpx(异步支持) |
8.5 官网介绍异步和同步
- 官网关于这个知识点的文字描述,有点意思:【 https://fastapi.tiangolo.com/zh/async/#_3 】
9、路由方案【重点】
9.1 请求方式划分
-
在开发 API 时,你通常使用特定的 HTTP 方法去执行特定的行为。通常使用:
-
POST:创建数据 -
GET:读取数据 -
PUT:更新数据 -
DELETE:删除数据
-
-
在 OpenAPI 中,每一个 HTTP 方法都被称为「操作」
9.2 路径装饰器
- 在 FastAPI 中,路径装饰器(Path Decorator) 是用来定义 接口的访问路径、请求方法 的。它告诉 FastAPI: “当用户访问某个路径时,用哪个函数来处理这个请求。”
- 通俗易懂:定义路由,提供给客户端,客户端通过这个路由访问服务器中该路由修饰的方法
9.2.1 常见的装饰器
| 装饰器 | HTTP 方法 | 说明 |
|---|---|---|
@app.get() |
GET | 获取数据(不修改服务器状态) |
@app.post() |
POST | 创建资源 |
@app.put() |
PUT | 更新资源(整体替换) |
@app.patch() |
PATCH | 局部更新资源 |
@app.delete() |
DELETE | 删除资源 |
@app.options() |
OPTIONS | 获取服务器支持的方法 |
@app.head() |
HEAD | 获取响应头(无响应体) |
9.2.2 路径参数
- resultful 风格,直接把参数值写在路径里面,没有参数名,请求路径定义变量接收,变量的值就是请求路径中的参数值【顺序】,然后接收到的参数给到函数的形式参数,形式参数名和请求路径定义变名字一样
- 路径中带变量(如
/users/{user_id})
@app.get("/users/{user_id}")
def get_user(user_id: int):
return {"user_id": user_id}
{user_id}是路径变量,FastAPI 会自动提取并转换为int类型。如果传入/users/10,返回{"user_id": 10}
9.2.3 查询参数
- 参数在请求路径后面(如
http://127.0.0.1:8000/search?q=fastapi&limit=5) - 方法的形式参数的名字和请求路径中的变量的 key 相同
@app.get("/search")
def search(q: str = None, limit: int = 10):
return {"query": q, "limit": limit}
9.2.4 请求体
- POST、PUT 请求用得比较多,DELETE、GET 不使用
from pydantic import BaseModel
class Item(BaseModel):
name: str
price: float
@app.post("/items")
def create_item(item: Item):
return {"received": item}
9.2.5 文件
- FastAPI 的文件上传、表单上传底层是依赖 python-multipart 包来解析请求体的
- 安装
python-multipart库
pip install python-multipart -i https://repo.huaweicloud.com/repository/pypi/simple/
- 接收上传的文件内容
@app.post("/upload")
async def upload_file(file: UploadFile = File(...)):
contents = await file.read()
return {
"filename": file.filename,
"content_type": file.content_type,
"size": len(contents)
}
- 如果既有文件又有其他字符串数据
@app.post("/upload")
async def upload_file(file: UploadFile = File(...), username: str = Form(...)):
print(usernmae)
contents = await file.read()
return {
"filename": file.filename,
"content_type": file.content_type,
"size": len(contents)
}
9.2.6 完整案例
-
先把入门案例代码删掉
-
编写接口方法,然后使用 APIPOST 进行接口测试、用 FastAPI 提供的 Swagger 也可以
-
get 请求测试【注意参数的2种不同的写法】
- post 请求测试
from pydantic import BaseModel
class User(BaseModel):
username: str
password: str

- post 上传文件测试

9.2.7 总结
- FastAPI 换了种操作方式,和 Django 相关操作没啥区别
10、跨域配置
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
# 允许访问的资源列表,* 表示任意
origins = [
"*",
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
11、数据库
- FastAPI 对 数据库访问方式并不限制,你可以直接用 PyMySQL(同步) 或 aiomysql(异步) 来操作 MySQL
- 不用去学习花里胡哨的 API
| 特点 | 同步 | 异步 |
|---|---|---|
| I/O 阻塞 | 会阻塞事件循环 | 不阻塞事件循环,可与 async/await 配合 |
| 使用场景 | 小型项目、简单 API | 高并发、大型项目、实时系统 |
| ORM 支持 | SQLAlchemy ORM(同步模式)、Django ORM | SQLAlchemy 1.4+ 异步模式、Tortoise ORM、Gino |
| 复杂性 | 简单,上手快 | 略复杂,需要 async/await 语法 |
- 同步:
import pymysql
from fastapi import FastAPI
app = FastAPI()
def get_connection():
return pymysql.connect(
host="localhost",
user="root",
password="root",
database="test",
cursorclass=pymysql.cursors.DictCursor
)
@app.get("/users")
def get_users():
conn = get_connection()
try:
with conn.cursor() as cursor:
cursor.execute("SELECT * FROM user")
result = cursor.fetchall()
return result
finally:
conn.close()
- 异步:每次请求都创建连接池不高效,实际项目通常在 启动时创建全局连接池
import aiomysql
from fastapi import FastAPI
app = FastAPI()
# 连接池
@app.on_event("startup")
async def startup_event():
app.state.db_pool = await aiomysql.create_pool(
host="localhost",
user="root",
password="123456",
db="test",
autocommit=True
)
@app.get("/users")
async def get_users():
pool = app.state.db_pool
async with pool.acquire() as conn:
async with conn.cursor(aiomysql.DictCursor) as cursor:
await cursor.execute("SELECT * FROM user")
result = await cursor.fetchall()
return result
- 总结:
- 小型项目:PyMySQL 够用
- 中大型或高并发项目:aiomysql + 全局连接池
12、静态资源
- 可以使用
StaticFiles从目录中自动提供静态文件
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
app.mount("/upload", StaticFiles(directory="upload"), name="upload")
- 以
static为例介绍,这个 "子应用" 会被 "挂载" 到第一个"/static"指向的子路径。因此,任何以"/static"开头的路径都会被它处理 directory="static"指向包含你的静态文件的目录名字name="static"提供了一个能被FastAPI内部使用的名字
13、jinja2 模板
- Jinja2 是 Python 的一个现代模板引擎(Template Engine),它用于将 Python 数据动态渲染成 HTML、XML、JSON 等文本格式
- 特点:
- 语法类似 Django 模板,但更灵活
- 支持模板继承(Template Inheritance)
- 支持变量替换、循环、条件判断、宏(macro)等
- 安全:默认会转义 HTML,防止 XSS 攻击
- 基本概念
| 概念 | 说明 | 示例 |
|---|---|---|
| 变量 | 用 {{ variable }} 输出变量值 |
{{ name }} |
| 表达式 | 支持运算或函数 | {{ 1 + 2 }} → 3 |
| 条件 | if / elif / else |
{% if user %}Hello {{ user }}{% endif %} |
| 循环 | for 循环列表或字典 |
{% for item in items %}{{ item }}{% endfor %} |
| 注释 | {# 注释内容 #} |
不会输出到页面 |
| 模板继承 | extends 和 block |
{% extends "base.html" %} |
13.1 使用案例
- FastAPI 提供了
fastapi.templating.Jinja2Templates封装,步骤如下 - 安装
jinja2库
pip install -i https://repo.huaweicloud.com/repository/pypi/simple/ jinja2
- 目录结构
stu_fastapi/
├── main.py
└── static/
└── templates/
└── index.html
- 案例代码
from fastapi import FastAPI, Request
from fastapi.templating import Jinja2Templates
from fastapi.responses import HTMLResponse
app = FastAPI()
templates = Jinja2Templates(directory="templates")
@app.get("/", response_class=HTMLResponse)
async def home(request: Request):
data = {"title": "首页", "user": {"name": "Tom"}, "items": ["苹果", "香蕉", "橘子"]}
return templates.TemplateResponse("index.html", {"request": request, **data})
- 页面代码:无需关心取值方式,反正不用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
</head>
<body>
<h1>Welcome {{ user.name }}!</h1>
<ul>
{% for item in items %}
<li>{{ item }}</li>
{% endfor %}
</ul>
</body>
</html>
14、流式输出
- 流式输出(Streaming Response)在 FastAPI 中主要用于逐步发送数据到客户端,而不是等整个响应完成才发送。常用于:
- 大文件下载
- 实时日志、聊天消息推送
- 数据生成流(如 AI 模型输出)
- FastAPI 提供了
StreamingResponse类,可以接受一个 可迭代对象 或 异步生成器 - 案例代码:SSE 可以在浏览器端实时接收事件流
import asyncio
async def event_generator():
for i in range(20):
yield f"data: message {i}\n\n"
await asyncio.sleep(1)
@app.get("/sse")
async def sse():
return StreamingResponse(event_generator(), media_type="text/event-stream")
15、父子路由
- 可以把路由定义在其他文件中,在 main.py 中引入进来
- 比如,在根目录下的
app/api/user.py中定义子路由
from fastapi import APIRouter
router = APIRouter()
@router.get("/users")
async def get_users():
return [{"id": 1, "name": "Tom"}, {"id": 2, "name": "Alice"}]
@router.get("/items")
async def get_items():
return [{"id": 1, "name": "Item1"}, {"id": 2, "name": "Item2"}]
main.py挂载
# 挂载子模块路由
app.include_router(users.router, prefix="/api/v1", tags=["users"])
app.include_router(users.router, prefix="/api/v1", tags=["items"])
- 挂载说明:
prefix:统一前缀/api/v1tags:用于 Swagger 文档分组- 访问:
GET http://127.0.0.1:8000/api/v1/users
GET http://127.0.0.1:8000/api/v1/items
16、配置启动
if __name__ == "__main__":
uvicorn.run(
"main:app",
host="127.0.0.1",
port=8081,
reload=True
)


浙公网安备 33010602011771号