2026-01-11 07:48:19 +08:00

173 lines
5.0 KiB
Python

"""
FastAPI 应用主文件
"""
import time
from fastapi import FastAPI, Request, status
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from fastapi.exceptions import RequestValidationError
from contextlib import asynccontextmanager
from app.core.config import settings
from app.core.response import error_response
from app.core.exceptions import BaseAPIException
from app.utils.logger import logger
from app.utils.monitor import api_monitor
from app.api.common.routes import router as common_router
from app.api.v1.inventory.routes import router as inventory_router
from app.api.v1.value.routes import router as value_router
from app.api.v1.delivery.routes import router as delivery_router
@asynccontextmanager
async def lifespan(app: FastAPI):
"""应用生命周期管理"""
# 启动时执行
logger.info("=" * 50)
logger.info(f"{settings.APP_NAME} 启动中...")
logger.info(f"版本: {settings.APP_VERSION}")
logger.info(f"调试模式: {settings.DEBUG}")
logger.info(f"环境变量: HOST={settings.HOST}, PORT={settings.PORT}")
logger.info("=" * 50)
yield
# 关闭时执行
logger.info(f"{settings.APP_NAME} 关闭中...")
# 创建 FastAPI 应用
app = FastAPI(
title=settings.APP_NAME,
version=settings.APP_VERSION,
description="数据资产盘点系统后端 API 服务",
docs_url="/docs",
redoc_url="/redoc",
openapi_url="/openapi.json",
lifespan=lifespan,
)
# 配置 CORS
app.add_middleware(
CORSMiddleware,
allow_origins=settings.CORS_ORIGINS,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# 添加监控中间件
@app.middleware("http")
async def monitoring_middleware(request: Request, call_next):
"""
监控中间件 - 记录所有 API 调用
Args:
request: 请求对象
call_next: 下一个中间件/路由处理器
Returns:
响应对象
"""
start_time = time.time()
endpoint = request.url.path
method = request.method
try:
# 调用下一个中间件/路由处理器
response = await call_next(request)
# 计算响应时间
response_time = (time.time() - start_time) * 1000 # 转换为毫秒
# 记录调用
api_monitor.record_call(
endpoint=endpoint,
method=method,
status_code=response.status_code,
response_time=response_time,
error=None
)
return response
except Exception as e:
# 计算响应时间
response_time = (time.time() - start_time) * 1000
# 记录调用(异常)
api_monitor.record_call(
endpoint=endpoint,
method=method,
status_code=500,
response_time=response_time,
error=str(e)
)
# 重新抛出异常,让全局异常处理器处理
raise
# 注册路由
app.include_router(common_router, prefix=settings.API_V1_PREFIX)
app.include_router(inventory_router, prefix=settings.API_V1_PREFIX)
app.include_router(value_router, prefix=settings.API_V1_PREFIX)
app.include_router(delivery_router, prefix=settings.API_V1_PREFIX)
# 异常处理器
@app.exception_handler(BaseAPIException)
async def base_api_exception_handler(request: Request, exc: BaseAPIException):
"""自定义 API 异常处理"""
logger.error(f"API 异常: {exc.message} | {exc.error_code}")
return JSONResponse(
status_code=exc.status_code,
content=error_response(
message=exc.message,
code=exc.status_code,
error_code=exc.error_code,
error_detail=exc.error_detail,
).dict(),
)
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
"""请求验证异常处理"""
logger.error(f"请求验证失败: {exc.errors()}")
return JSONResponse(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
content=error_response(
message="请求参数验证失败",
code=status.HTTP_422_UNPROCESSABLE_ENTITY,
error_code="VALIDATION_ERROR",
error_detail=exc.errors(),
).dict(),
)
@app.exception_handler(Exception)
async def general_exception_handler(request: Request, exc: Exception):
"""通用异常处理"""
logger.exception(f"未处理的异常: {str(exc)}")
return JSONResponse(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
content=error_response(
message="服务器内部错误",
code=status.HTTP_500_INTERNAL_SERVER_ERROR,
error_code="INTERNAL_SERVER_ERROR",
error_detail=str(exc) if settings.DEBUG else None,
).dict(),
)
if __name__ == "__main__":
import uvicorn
uvicorn.run(
"app.main:app",
host=settings.HOST,
port=settings.PORT,
reload=settings.DEBUG,
log_level=settings.LOG_LEVEL.lower(),
)