文章目录
- [创建FastAPI 应用](#创建FastAPI 应用)
-
- 数据验证
- [Pydantic 模型](#Pydantic 模型)
- 路由分发
- Request对象
- uvicorn.run()
- 异步特性
FastAPI 是主打高性能 API 开发的现代化 Python 框架,核心基于异步 ASGI 协议和 Pydantic 数据校验,对比 Flask、Django 的核心优势可总结为:
- 性能更高:异步原生设计,高并发场景下性能远超同步的 Flask/Django;
- 开发更快:自动生成交互式 API 文档、自动校验请求参数,无需手写重复代码,效率远高于需手动扩展的 Flask 和配置繁琐的Django+DRF;
- 简洁且规范:语法接近 Flask 的轻量化,同时内置 OpenAPI 规范,无需像 Flask 那样靠扩展补全 API 能力,也比Django 更轻量。
创建FastAPI 应用
创建main.py文件
python
from fastapi import FastAPI
# 创建FastAPI应用实例
@app.get("/hello/{name}")
async def say_hello(name: str, age: int = None):
"""
路径参数name:必填,字符串类型
查询参数age:可选,整数类型,默认值为None
"""
if age:
return {"message": f"Hello {name}, you are {age} years old!"}
return {"message": f"Hello {name}!"}
创建虚拟环境
python
# Linux/Mac
python3 -m venv fastapi-env
# Windows
python -m venv fastapi-env
激活虚拟环境
python
# Linux/Mac
source fastapi-env/bin/activate
# Windows
fastapi-env\Scripts\activate.bat
激活后安装 uvicorn
python
pip install uvicorn fastapi
启动服务
python
uvicorn main:app --reload
--reload:热重载模式,代码修改后自动重启服务
访问 http://127.0.0.1:8000/hello/yww

访问 http://127.0.0.1:8000/docs,通过 Swagger UI 可视化测试接口
注:
- 参数传递需严格匹配定义:路径参数必填,查询参数可选,多传或少传会返回 422 错误
- 数据类型需符合注解:如将非整数传入age参数,会自动返回参数校验错误
- 浏览器默认支持 GET 请求,POST、PUT 等请求需通过Apifox、Postman 等工具测试
数据验证
python
from typing import Optional
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def get_item(
# 路径参数:必须大于0的整数
item_id: int = Path(..., ge=1, description="ID必须为正整数"),
# 查询参数:可选字符串,默认值为None
q: Optional[str] = None
):
return {"item_id": item_id, "q": q}
非法请求http://127.0.0.1:8000/items/0?q=abc

合法请求http://127.0.0.1:8000/items/10?q=abc

Pydantic 模型
python
from typing import Optional
from pydantic import BaseModel
from fastapi import FastAPI
app = FastAPI()
# 定义请求体数据模型
class Item(BaseModel):
name: str
price: float
is_offer: Optional[bool] = None # 可选字段,默认值None
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
"""更新商品信息,请求体需符合Item模型结构"""
return {
"item_id": item_id,
"item_name": item.name,
"item_price": item.price,
"is_offer": item.is_offer
}
路由装饰器@app.put指定,浏览器无法直接访问,需用 Postman/Apifox/curl
curl访问

文档接口访问
访问http://127.0.0.1:8000/docs → PUT /items/{item_id}接口 → "Try it out"


路由分发
路由分发可以将不同业务模块的接口路由拆分到独立文件中管理,解决单文件路由臃肿、维护困难、协作低效的问题,同时保持接口结构清晰、可扩展、可复用。
python
# routes/book.py
from fastapi import APIRouter
# 创建路由实例,指定模块标签
book_router = APIRouter(tags=["图书管理"])
@book_router.get("/books")
async def get_books():
return {"message": "获取所有图书"}
@book_router.post("/createBooks")
async def create_book():
return {"message": "创建新图书"}
python
# routes/user.py
from fastapi import APIRouter
user_router = APIRouter(tags=["用户管理"])
@user_router.get("/users")
async def get_users():
return {"message": "获取所有用户"}
@user_router.post("/createUsers")
async def create_user():
return {"message": "创建新用户"}
在main.py中统一注册路由:
python
from fastapi import FastAPI
from routes.book import book_router
from routes.user import user_router
app = FastAPI(title="模块化API示例", version="1.0")
# 注册路由,添加路径前缀
app.include_router(book_router, prefix="/api")
app.include_router(user_router, prefix="/api")
python
# 获取所有图书(GET)
curl http://127.0.0.1:8000/api/books
# 创建用户(POST)
curl -X POST http://127.0.0.1:8000/api/createUsers

Request对象
当需要直接获取请求上下文信息(如客户端 IP、请求头、Cookie 等)时,可使用Request对象:

python
from fastapi import FastAPI, Request
app = FastAPI()
@app.post("/request-info")
async def get_request_info(request: Request):
# 获取请求核心信息
return {
"client_ip": request.client.host,
"request_method": request.method,
"request_url": str(request.url),
"headers": dict(request.headers),
"query_params": dict(request.query_params),
"path_params": dict(request.path_params)
}
python
# 基础测试
curl -X POST http://127.0.0.1:8000/request-info
# 带查询参数测试
curl -X POST "http://127.0.0.1:8000/request-info?name=czl&age=26"

uvicorn.run()
以上FastAPI 服务都要手动在终端输入uvicorn 文件名:app --reload很麻烦,可通过uvicorn直接运行,uvicorn.run()是 Uvicorn 库提供的编程式启动方法,相当于把终端命令写进代码里,运行 Python 文件时会自动触发服务启动,和手动输uvicorn main:app --reload效果完全一致,还能自定义端口、是否热重载等参数。
python
from fastapi import FastAPI, Request
import uvicorn
app = FastAPI()
@app.post("/request-info")
async def get_request_info(request: Request):
return {
"client_ip": request.client.host,
"request_method": request.method,
"request_url": str(request.url),
"headers": dict(request.headers),
"query_params": dict(request.query_params),
"path_params": dict(request.path_params)
}
if __name__ == "__main__":
# uvicorn.run()参数说明:
# - app:指定要启动的FastAPI应用实例(对应终端命令的"main:app")
# - host:绑定的IP,"0.0.0.0"允许局域网访问,"127.0.0.1"仅本机访问
# - port:端口号,默认8000,可自定义(如8080)
# - reload:是否开启热重载(开发环境必开,代码修改自动重启服务)
# - log_level:日志级别,可选"info"/"debug"/"error"等
uvicorn.run(
app="__main__:app", # 格式:"模块名:应用实例名",__main__表示当前文件
host="127.0.0.1",
port=8000,
reload=True,
log_level="info"
)
异步特性
同步 vs 异步的本质区别
- 同步框架(Flask/Django):基于 WSGI 协议,每个请求占用一个线程,遇到 IO操作(如数据库查询、调用第三方接口、文件读写)时,线程会阻塞等待结果返回,期间无法处理其他请求,高并发下易出现线程耗尽、响应超时。
- 异步框架(FastAPI):基于 ASGI 协议,请求由事件循环(Event Loop)管理,遇到 IO 操作时,线程不会阻塞,而是挂起当前请求,去处理其他请求,当 IO 操作完成后,再回到该请求继续处理,极大提升了 IO 密集型场景的并发能力。
FastAPI 的异步语法基于 Python 3.5 + 的async/await关键字:
- async def:定义异步函数,函数内部可执行异步操作;
- await:等待异步操作完成(如异步数据库查询、异步 HTTP 请求),且不会阻塞事件循环。
python
import uvicorn
from fastapi import FastAPI
import asyncio
app = FastAPI(title="异步特性示例")
# 同步函数:模拟IO操作
def sync_io_operation():
"""同步IO:阻塞线程"""
import time
time.sleep(2) # 模拟2秒IO等待(阻塞)
return "同步IO完成"
# 异步函数:模拟IO操作
async def async_io_operation():
"""异步IO:不阻塞线程"""
await asyncio.sleep(2) # 模拟2秒IO等待(非阻塞)
return "异步IO完成"
# 同步接口
@app.get("/sync")
def sync_endpoint():
result = sync_io_operation()
return {"message": result, "type": "同步接口"}
# 异步接口(async def + await)
@app.get("/async")
async def async_endpoint():
result = await async_io_operation()
return {"message": result, "type": "异步接口"}
if __name__ == "__main__":
uvicorn.run(
app="__main__:app",
host="127.0.0.1",
port=8000,
reload=True,
log_level="info"
)
- 同步接口/sync:同时发送 10 个请求,总耗时≈20 秒(每个请求阻塞 2 秒,串行处理);
- 异步接口/async:同时发送 10 个请求,总耗时≈2 秒(所有请求并行等待 IO,事件循环统一调度)。
注意:
FastAPI 对同步接口的处理逻辑:同步函数会被自动放入线程池执行,默认线程池大小是40,也就是说默认的线程池配置让同步接口也实现了40个请求的并行处理,所以同时发送10个请求到同步接口和异步接口的处理总耗时差不多,但该并行是基于多线程的阻塞式并行,当请求数超过 40 时,超出的请求会排队,耗时随请求数线性增长。
异步调用天气接口
python
from fastapi import FastAPI, Response
import uvicorn
app = FastAPI()
from fastapi import FastAPI
import aiohttp
app = FastAPI()
@app.get("/async-weather", responses={200: {"content": {"application/json; charset=utf-8": {}}}})
async def get_weather(city: str, response: Response):
response.headers["Content-Type"] = "application/json; charset=utf-8"
async with aiohttp.ClientSession() as session:
async with session.get(
url=f"http://api.weatherapi.com/v1/current.json?key=aa23da4921fe41a083717631934252912&q={city}",
headers={"Accept-Charset": "utf-8"}
) as resp:
data = await resp.json(encoding="utf-8")
weather = data["current"]["condition"]["text"]
return {"city": city, "weather": weather}
if __name__ == "__main__":
uvicorn.run(
app="__main__:app",
host="127.0.0.1",
port=8000,
reload=True,
log_level="info"
)
python
#访问
http://127.0.0.1:8000/async-weather?city=广东
