百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

高级 FastAPI 模式:使用 Python 构建可用于生产的 API

itomcoil 2025-03-14 18:07 30 浏览

FastAPI 以其现代的异步优先方法彻底改变了 Python API 开发。我花了大量时间研究 FastAPI,我将分享在生产环境中行之有效的高级模式。

依赖注入

FastAPI 中的依赖注入提供了清晰的关注点分离和高效的资源管理。以下是数据库依赖项的实际实现:

from fastapi import Depends
from sqlalchemy.orm import Session
from contextlib import contextmanager

class Database:
    def __init__(self):
        self.session = None

    @contextmanager
    def get_session(self):
        session = Session()
        try:
            yield session
        finally:
            session.close()

db = Database()

async def get_db():
    with db.get_session() as session:
        yield session

@app.get("/users/{user_id}")
async def get_user(user_id: int, db: Session = Depends(get_db)):
    return db.query(User).filter(User.id == user_id).first()

响应缓存

实现 Redis 缓存可显著提高 API 性能。以下是一个强大的缓存实现:

from fastapi_cache import FastAPICache
from fastapi_cache.backends.redis import RedisBackend
import pickle

class CustomRedisBackend(RedisBackend):
    async def get(self, key: str):
        value = await self.redis.get(key)
        if value:
            return pickle.loads(value)
        return None

    async def set(self, key: str, value: any, expire: int = None):
        value = pickle.dumps(value)
        await self.redis.set(key, value, expire)

@app.on_event("startup")
async def startup():
    redis = aioredis.Redis(host='localhost', port=6379)
    FastAPICache.init(CustomRedisBackend(redis), prefix="fastapi-cache:")

@app.get("/products/{product_id}")
@FastAPICache.cache(expire=300)
async def get_product(product_id: int):
    return {"product_id": product_id}

后台任务

有效地管理长时间运行的操作至关重要。以下是处理后台任务的模式:

from fastapi import BackgroundTasks
from celery import Celery

celery_app = Celery('tasks', broker='redis://localhost:6379/0')

@celery_app.task
def process_video(video_id: int):
    # Video processing logic
    pass

@app.post("/videos/")
async def upload_video(
    video: UploadFile,
    background_tasks: BackgroundTasks
):
    video_id = save_video(video)
    background_tasks.add_task(process_video.delay, video_id)
    return {"status": "processing"}

速率限制

保护 API 资源需要有效的速率限制。以下是基于 Redis 的实现:

from fastapi import HTTPException
import time

class RateLimiter:
    def __init__(self, redis_client, limit: int, window: int):
        self.redis = redis_client
        self.limit = limit
        self.window = window

    async def is_allowed(self, key: str) -> bool:
        current = int(time.time())
        window_start = current - self.window

        async with self.redis.pipeline() as pipe:
            pipe.zremrangebyscore(key, 0, window_start)
            pipe.zadd(key, {str(current): current})
            pipe.zcard(key)
            pipe.expire(key, self.window)
            results = await pipe.execute()

        return results[2] <= self.limit

@app.get("/api/resource")
async def get_resource(
    redis: Redis = Depends(get_redis),
    user: User = Depends(get_current_user)
):
    rate_limiter = RateLimiter(redis, limit=100, window=3600)
    if not await rate_limiter.is_allowed(f"rate_limit:{user.id}"):
        raise HTTPException(status_code=429, detail="Rate limit exceeded")
    return {"data": "resource"}

自定义中间件

中间件提供了强大的请求/响应修改功能:

from fastapi import Request
from fastapi.middleware.base import BaseHTTPMiddleware
import time

class TimingMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        start_time = time.time()
        response = await call_next(request)
        process_time = time.time() - start_time
        response.headers["X-Process-Time"] = str(process_time)
        return response

app.add_middleware(TimingMiddleware)

API 版本控制

维护 API 版本对于向后兼容性至关重要:

from fastapi import APIRouter

v1_router = APIRouter(prefix="/v1")
v2_router = APIRouter(prefix="/v2")

@v1_router.get("/users/{user_id}")
async def get_user_v1(user_id: int):
    return {"version": "1", "user_id": user_id}

@v2_router.get("/users/{user_id}")
async def get_user_v2(user_id: int):
    return {"version": "2", "user_id": user_id}

app.include_router(v1_router)
app.include_router(v2_router)

错误处理

一致的错误处理提高了 API 的可靠性:

from fastapi import HTTPException
from fastapi.responses import JSONResponse

class CustomException(Exception):
    def __init__(self, message: str, code: str):
        self.message = message
        self.code = code

@app.exception_handler(CustomException)
async def custom_exception_handler(request, exc):
    return JSONResponse(
        status_code=400,
        content={
            "error": {
                "code": exc.code,
                "message": exc.message
            }
        }
    )

@app.get("/items/{item_id}")
async def get_item(item_id: int):
    if item_id < 0:
        raise CustomException(
            message="Invalid item ID",
            code="INVALID_ID"
        )
    return {"item_id": item_id}

测试

全面的测试确保API的可靠性:

from fastapi.testclient import TestClient
import pytest

client = TestClient(app)

@pytest.fixture
def test_db():
    # Setup test database
    db = Database()
    yield db
    # Cleanup

def test_read_item():
    response = client.get("/items/1")
    assert response.status_code == 200
    assert response.json() == {"item_id": 1}

def test_create_item():
    response = client.post(
        "/items/",
        json={"name": "Test Item"}
    )
    assert response.status_code == 201

生产部署

对于生产部署,请考虑以下配置:

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
import uvicorn

app = FastAPI(
    title="Production API",
    description="Production-ready FastAPI application",
    version="1.0.0",
    docs_url="/documentation",
    redoc_url=None
)

app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://allowed-domain.com"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

if __name__ == "__main__":
    uvicorn.run(
        "main:app",
        host="0.0.0.0",
        port=8000,
        workers=4,
        log_level="info",
        reload=False
    )

这些模式构成了强大的 FastAPI 应用程序的基础。异步功能与适当的资源管理和错误处理相结合,可创建高性能 API。定期测试和监控可确保生产环境中的可靠性。

请记住根据特定要求和规模调整这些模式。FastAPI 的灵活性允许自定义,同时保持性能和代码清晰度。

相关推荐

python创建文件夹,轻松搞定,喝咖啡去了

最近经常在录视频课程,一个课程下面往往有许多小课,需要分多个文件夹来放视频、PPT和案例,这下可好了,一个一个手工创建,手酸了都做不完。别急,来段PYTHON代码,轻松搞定,喝咖啡去了!import...

如何编写第一个Python程序_pycharm写第一个python程序

一、第一个python程序[掌握]python:python解释器,将python代码解释成计算机认识的语言pycharm:IDE(集成开发环境),写代码的一个软件,集成了写代码,...

Python文件怎么打包为exe程序?_python3.8打包成exe文件

PyInstaller是一个Python应用程序打包工具,它可以将Python程序打包为单个独立可执行文件。要使用PyInstaller打包Python程序,需要在命令行中使用py...

官方的Python环境_python环境版本

Python是一种解释型编程开发语言,根据Python语法编写出来的程序,需要经过Python解释器来进行执行。打开Python官网(https://www.python.org),找到下载页面,选择...

[编程基础] Python配置文件读取库ConfigParser总结

PythonConfigParser教程显示了如何使用ConfigParser在Python中使用配置文件。文章目录1介绍1.1PythonConfigParser读取文件1.2Python...

Python打包exe软件,用这个库真的很容易

初学Python的人会觉得开发一个exe软件非常复杂,其实不然,从.py到.exe文件的过程很简单。你甚至可以在一天之内用Python开发一个能正常运行的exe软件,因为Python有专门exe打包库...

2025 PyInstaller 打包说明(中文指南),python 打包成exe 都在这里

点赞标记,明天就能用上这几个技巧!linux运维、shell、python、网络爬虫、数据采集等定定做,请私信。。。PyInstaller打包说明(中文指南)下面按准备→基本使用→常用...

Python自动化办公应用学习笔记40—文件路径2

4.特殊路径操作用户主目录·获取当前用户的主目录路径非常常用:frompathlibimportPathhome_dir=Path.home()#返回当前用户主目录的Path对象...

Python内置tempfile模块: 生成临时文件和目录详解

1.引言在Python开发中,临时文件和目录的创建和管理是一个常见的需求。Python提供了内置模块tempfile,用于生成临时文件和目录。本文将详细介绍tempfile模块的使用方法、原理及相关...

python代码实现读取文件并生成韦恩图

00、背景今天战略解码,有同学用韦恩图展示各个产品线的占比,效果不错。韦恩图(Venndiagram),是在集合论数学分支中,在不太严格的意义下用以表示集合的一种图解。它们用于展示在不同的事物群组之...

Python技术解放双手,一键搞定海量文件重命名,一周工作量秒搞定

摘要:想象一下,周五傍晚,办公室的同事们纷纷准备享受周末,而你,面对着堆积如山的文件,需要将它们的文件名从美国日期格式改为欧洲日期格式,这似乎注定了你将与加班为伍。但别担心,Python自动化办公来...

Python路径操作的一些基础方法_python路径文件

带你走进@机器人时代Discover点击上面蓝色文字,关注我们Python自动化操作文件避开不了路径操作方法,今天我们来学习一下路径操作的一些基础。Pathlib库模块提供的路径操作包括路径的...

Python爬取下载m3u8加密视频,原来这么简单

1.前言爬取视频的时候发现,现在的视频都是经过加密(m3u8),不再是mp4或者avi链接直接在网页显示,都是经过加密形成ts文件分段进行播放。今天就教大家如果通过python爬取下载m3u8加密视频...

探秘 shutil:Python 高级文件操作的得力助手

在Python的标准库中,shutil模块犹如一位技艺精湛的工匠,为我们处理文件和目录提供了一系列高级操作功能。无论是文件的复制、移动、删除,还是归档与解压缩,shutil都能以简洁高效的方式完成...

怎么把 Python + Flet 开发的程序,打包为 exe ?这个方法很简单!

前面用Python+Flet开发的“我的计算器v3”,怎么打包为exe文件呢?这样才能分发给他人,直接“双击”运行使用啊!今天我给大家分享一个简单的、可用的,把Flet开发的程序打包为...