python API 之 fastapi

news/2025/4/2 11:44:10/文章来源:https://www.cnblogs.com/itech/p/18803139

 

为什么选择 FastAPI?

  • 高性能:基于 Starlette 和 Uvicorn,支持异步请求处理

  • 开发效率:自动交互文档、类型提示、代码自动补全

  • 现代标准:兼容 OpenAPI 和 JSON Schema

  • 易扩展:模块化设计,支持中间件和依赖注入

 

以下是一个使用 FastAPI 最新特性 (0.109+) 的完整示例,涵盖核心功能并包含详细注释:

```python
# main.py
from typing import Annotated, Optional
from datetime import datetime, timedelta
from contextlib import asynccontextmanagerfrom fastapi import (
    FastAPI, 
    Depends, 
    HTTPException, 
    status, 
    Query, 
    Body,
    WebSocket,
    Request
)
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from fastapi.responses import HTMLResponse
from pydantic import BaseModel, EmailStr, Field
from jose import JWTError, jwt
from passlib.context import CryptContext# ---------------------------
# 应用生命周期与配置
# ---------------------------
@asynccontextmanager
async def lifespan(app: FastAPI):
    """生命周期管理 (FastAPI 2.2+ 新特性)"""
    print("Application startup")
    yield
    print("Application shutdown")app = FastAPI(
    title="Modern FastAPI Demo",
    lifespan=lifespan,
    swagger_ui_parameters={"syntaxHighlight": False}
)# 配置中间件
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)# 静态文件服务
app.mount("/static", StaticFiles(directory="static"), name="static")
templates = Jinja2Templates(directory="templates")# ---------------------------
# 安全配置
# ---------------------------
SECRET_KEY = "your-secret-key-keep-it-secret"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")# ---------------------------
# 数据模型
# ---------------------------
class UserBase(BaseModel):
    username: str = Field(..., example="john_doe")
    email: EmailStr = Field(..., example="john@example.com")class UserCreate(UserBase):
    password: str = Field(..., min_length=8, example="secret123")class UserInDB(UserBase):
    hashed_password: strclass Token(BaseModel):
    access_token: str
    token_type: strclass TokenData(BaseModel):
    username: Optional[str] = None# ---------------------------
# 工具函数
# ---------------------------
def fake_hash_password(password: str):
    return pwd_context.hash(password)def verify_password(plain_password: str, hashed_password: str):
    return pwd_context.verify(plain_password, hashed_password)def create_access_token(data: dict, expires_delta: timedelta):
    to_encode = data.copy()
    expire = datetime.utcnow() + expires_delta
    to_encode.update({"exp": expire})
    return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)# ---------------------------
# 依赖项
# ---------------------------
async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username: str = payload.get("sub")
        if username is None:
            raise credentials_exception
        token_data = TokenData(username=username)
    except JWTError:
        raise credentials_exception
    # 这里应查询真实数据库
    user = UserInDB(
        username=token_data.username,
        email="user@example.com", 
        hashed_password="fakehashedsecret"
    )
    return user# ---------------------------
# 路由
# ---------------------------
@app.get("/", response_class=HTMLResponse)
async def read_root(request: Request):
    """返回HTML页面 (集成前端示例)"""
    return templates.TemplateResponse(
        "index.html",
        {"request": request, "message": "Welcome to FastAPI!"}
    )@app.post("/users/", status_code=status.HTTP_201_CREATED)
async def create_user(user: UserCreate):
    """创建用户 (数据验证示例)"""
    hashed_password = fake_hash_password(user.password)
    return {
        "username": user.username,
        "email": user.email,
        "hashed_password": hashed_password
    }@app.post("/token", response_model=Token)
async def login_for_access_token(
    form_data: Annotated[OAuth2PasswordRequestForm, Depends()]
):
    """OAuth2 认证 (安全示例)"""
    # 验证用户逻辑应替换为真实数据库查询
    user = UserInDB(
        username=form_data.username,
        email="user@example.com",
        hashed_password=fake_hash_password(form_data.password)
    )
    if not verify_password(form_data.password, user.hashed_password):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
        )
    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(
        data={"sub": user.username}, 
        expires_delta=access_token_expires
    )
    return {"access_token": access_token, "token_type": "bearer"}@app.get("/users/me")
async def read_users_me(
    current_user: Annotated[UserInDB, Depends(get_current_user)]
):
    """需要认证的端点示例"""
    return current_user@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    """WebSocket 示例"""
    await websocket.accept()
    while True:
        data = await websocket.receive_text()
        await websocket.send_text(f"Message received: {data}")@app.get("/items/")
async def read_items(
    q: Annotated[
        Optional[str], 
        Query(
            title="Query string",
            description="Optional search query",
            min_length=3,
            max_length=50
        )
    ] = None,
    page: Annotated[int, Query(ge=1)] = 1,
    size: Annotated[int, Query(ge=1, le=100)] = 10
):
    """复杂查询参数示例"""
    return {"q": q, "page": page, "size": size}@app.post("/compute/")
async def compute_task(
    numbers: Annotated[list[int], Body(embed=True)],
    delay: Annotated[bool, Body()] = False
):
    """后台任务示例"""
    if delay:
        # 模拟长时间任务
        import time
        time.sleep(2)
    
    total = sum(numbers)
    return {"total": total, "count": len(numbers)}# ---------------------------
# 错误处理
# ---------------------------
@app.exception_handler(HTTPException)
async def http_exception_handler(request, exc):
    return JSONResponse(
        status_code=exc.status_code,
        content={"detail": exc.detail},
        headers=exc.headers
    )# ---------------------------
# 运行与测试
# ---------------------------
if __name__ == "__main__":
    import uvicorn
    uvicorn.run(
        "main:app",
        host="0.0.0.0", 
        port=8000,
        reload=True,
        ssl_keyfile="key.pem",  # HTTPS 示例(需生成证书)
        ssl_certfile="cert.pem"
    )
```

### 配套文件结构
```
project/
├── static/
│   └── style.css
├── templates/
│   └── index.html
├── main.py
├── requirements.txt
├── cert.pem
└── key.pem
```

### 主要功能说明

1. **最新生命周期管理**  
使用 `@asynccontextmanager` 管理应用生命周期(FastAPI 2.2+)

2. **安全认证系统**  
- OAuth2 密码流认证
- JWT Token 生成与验证
- 密码哈希加密(使用 passlib)

3. **现代化数据验证**  
- Pydantic V2 模型验证
- 参数注解式声明(Annotated)
- 复杂查询参数约束

4. **高级路由功能**  
- WebSocket 支持
- 静态文件服务
- Jinja2 模板渲染
- 后台任务处理

5. **生产级配置**  
- CORS 中间件
- HTTPS 支持
- 结构化错误处理
- 自动生成文档(Swagger/ReDoc)

6. **类型提示增强**  
- 使用 Python 3.10+ 的类型注解
- 依赖注入系统增强
- 参数元数据声明

### 运行与测试

1. 安装依赖:
```bash
pip install fastapi uvicorn[standard] python-jose[cryptography] passlib jinja2
```

2. 启动服务:
```bash
python main.py
```

3. 访问功能:
- API 文档:`https://localhost:8000/docs`
- WebSocket 测试:`ws://localhost:8000/ws`
- 前端页面:`https://localhost:8000/`

### 测试示例(使用 HTTPie)
```bash
# 创建用户
http POST :8000/users/ username=john email=john@test.com password=secret123

# 获取Token
http POST :8000/token username=john password=secret123

# 访问受保护端点
http GET :8000/users/me "Authorization: Bearer <token>"

# WebSocket测试
websocat ws://localhost:8000/ws
```

这个示例展示了 FastAPI 的现代用法,包含最新的特性实现方式,建议结合官方文档和实际项目需求进行扩展。

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/908859.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《HarmonyOS Next开发进阶:打造功能完备的Todo应用华章》

章节 6:日期选择器与日期处理目标学习如何使用DatePicker组件。 理解日期格式化和日期计算。内容日期选择器基础使用DatePicker组件。 处理日期选择事件。日期格式化格式化日期为友好的文本。日期计算判断日期是否过期或即将到期。代码示例 @Entry @Component struct DatePick…

MarkDwon语法

MarkDown语法 1、标题用法 一级标题:#+空格+内容+回车 二级标题:##+空格+内容+回车 三级标题:###+空格+内容+回车 四级标题:####+空格+内容+回车 2、字体用法 粗体使用:快捷键ctrl+b或者内容两边加两个星号,示例 斜体使用:内容两边加一个星号,示例 斜体加粗:内容两边加…

图论(连通分量)

AT_abc284_c [ABC284C] Count Connected Components 题目描述 頂点に $ 1 $ から $ N $ の番号が、辺に $ 1 $ から $ M $ の番号がついた $ N $ 頂点 $ M $ 辺の単純無向グラフが与えられます。辺 $ i $ は頂点 $ u_i $ と頂点 $ v_i $ を結んでいます。 グラフに含まれる連結…

业务系统基础框架-Winform版-角色

角色列表,可刷新,可展开,可折叠编辑角色为角色权限为角色分配菜单查看拥有此角色的账号

3.31 学习记录

实现了使用springboot从文件中读取数据显示在前端

记一次GC导致线上服务超时问题

1、现象2024-12-28 23点左右,线上其他服务请求 content-cache 出现批量超时。content-cache-03 机器内存使用率如下:机器配置:4核8G这里因为JVM参数设置为:-Xms4g -Xmx4g -XX:MaxNewSize=1g所以达到42%时,内存的使用率已经达到了3.3G。 2、数据查看GC日志如下: (1)CMS老…

No.1 可视化大屏--vite+vue3项目环境搭建

一、DataV-Vue3 1.1 安装 官网:https://datav-vue3.netlify.app/Guide/Guide.htmlnpm install @kjgl77/datav-vue3 一、vite3构建Vue3项目 1.1 什么是Vite 1.2创建vite3项目 第一步:新建一个项目的文件夹第二步:输入cmd,回车 第三步: npm init vite 第四步:输入项目名称…

SvelteKit 最新中文文档教程(16)—— Service workers

前言 Svelte,一个语法简洁、入门容易,面向未来的前端框架。 从 Svelte 诞生之初,就备受开发者的喜爱,根据统计,从 2019 年到 2024 年,连续 6 年一直是开发者最感兴趣的前端框架 No.1:Svelte 以其独特的编译时优化机制著称,具有轻量级、高性能、易上手等特性,非常适合构…

OLLAMA 自定义大模型角色

在Ollama中通过deepseek-r1生成特定角色的模板(如教案设计),核心是通过Modelfile定义模型的系统提示(SYSTEM)和对话模板(TEMPLATE)。以下是具体步骤和示例: 一、Modelfile 基本结构与关键指令FROM指令指定基础模型,这里你可以使用ollama本地下载的模型,也可以去Huggi…

WebSocket调试神器对决:Apipost凭何碾压Apifox?

你以为所有API工具都能玩转WebSocket? 当你的APP需要实时股票行情推送,当你的游戏要处理千人同屏交互,当你的IM系统必须保障消息零延迟——传统HTTP协议的"一问一答"模式瞬间破功。此刻WebSocket协议才是真正的救世主,这个全双工通信协议能让客户端与服务器建立&…

一年前的无心之举,一年后我想要将其做的更好——公众号开通。

大家好,答应的事情要做到。 我是晚秋,我在这里,这是我的公众号。 一年前我想把学过的技术,解决得问题都记录下来,帮助更多的人。 日复一日,也放弃过。 但是到今日,忽然看到自己的无心之举帮助了很多刚进入技术这一行的人。 他们迷茫,他们困顿,正如当初的我一样。 谢谢…