"""FastAPI 应用入口""" import uuid from contextlib import asynccontextmanager from fastapi import FastAPI, Request from fastapi.middleware.cors import CORSMiddleware from app.config import settings from app.core.response import register_exception_handlers, request_id_ctx from app.database import engine from app.redis_client import redis_client @asynccontextmanager async def lifespan(app: FastAPI): # 周期任务(推荐激活/创作收益/超时关单),进程退出时取消 from app.services import settle_service tasks = settle_service.start_periodic_tasks() yield for t in tasks: t.cancel() # 关闭连接池 await redis_client.aclose() await engine.dispose() app = FastAPI( title="短视频应用 API", version="1.0.0", lifespan=lifespan, docs_url="/docs" if settings.app_env == "dev" else None, redoc_url=None, ) app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) @app.middleware("http") async def request_id_middleware(request: Request, call_next): """request_id 贯穿:优先取客户端 X-Request-ID,否则生成""" rid = request.headers.get("X-Request-ID") or str(uuid.uuid4()) request_id_ctx.set(rid) response = await call_next(request) response.headers["X-Request-ID"] = rid return response register_exception_handlers(app) @app.get("/health", include_in_schema=False) async def health() -> dict: return {"status": "ok"} # 本地文件存储(开发环境):/static 访问 server/uploads from fastapi.staticfiles import StaticFiles from app.config import BASE_DIR (BASE_DIR / "uploads").mkdir(parents=True, exist_ok=True) app.mount("/static", StaticFiles(directory=BASE_DIR / "uploads"), name="static") # 业务路由(按模块逐步注册) from app.api.v1 import admin, auth, common, incentives, interactions, invite, media, membership, payments, users, videos app.include_router(media.router, prefix="/api/v1") app.include_router(auth.router, prefix="/api/v1") app.include_router(users.router, prefix="/api/v1") app.include_router(videos.router, prefix="/api/v1") app.include_router(videos.router_tags, prefix="/api/v1") app.include_router(videos.router_search, prefix="/api/v1") app.include_router(interactions.router_videos, prefix="/api/v1") app.include_router(interactions.router_comments, prefix="/api/v1") app.include_router(membership.router, prefix="/api/v1") app.include_router(payments.router, prefix="/api/v1") app.include_router(payments.router_callbacks, prefix="/api/v1") app.include_router(incentives.router_referral, prefix="/api/v1") app.include_router(incentives.router_assets, prefix="/api/v1") app.include_router(common.router, prefix="/api/v1") app.include_router(admin.router, prefix="/api/v1") app.include_router(invite.router, prefix="/api/v1") # 推广落地页(根路径 /r/{code},对应 referral/me 返回的 invite_url) app.include_router(invite.router_page)