main.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. """
  2. FastAPI应用入口
  3. """
  4. from fastapi import FastAPI, Request
  5. from fastapi.middleware.cors import CORSMiddleware
  6. from fastapi.responses import JSONResponse
  7. from app.api.client import router as client_router
  8. from app.api.admin import router as admin_router
  9. from app.core.logger import setup_logger
  10. from app.core.init_keys import init_keys
  11. from app.middleware.logging import APILoggingMiddleware
  12. from app.utils.exceptions import BusinessException
  13. from app.background_tasks import lifespan_manager
  14. # 设置日志
  15. logger = setup_logger()
  16. # 初始化密钥对
  17. try:
  18. init_keys()
  19. logger.info("基础密钥初始化完成")
  20. except Exception as e:
  21. logger.exception("基础密钥初始化失败")
  22. # 初始化密钥轮换系统
  23. try:
  24. from app.services.key_rotation_service import KeyRotationService
  25. from app.database import get_db
  26. db = next(get_db())
  27. if KeyRotationService.initialize_keys(db):
  28. logger.info("密钥轮换系统初始化成功")
  29. else:
  30. logger.error("密钥轮换系统初始化失败")
  31. db.close()
  32. except Exception as e:
  33. logger.exception("密钥轮换系统初始化异常")
  34. # 初始化Session清理
  35. try:
  36. from app.services.session_service import SessionService
  37. from app.database import get_db
  38. db = next(get_db())
  39. cleaned_count = SessionService.cleanup_expired_sessions(db)
  40. if cleaned_count > 0:
  41. logger.info(f"清理了 {cleaned_count} 个过期会话")
  42. else:
  43. logger.info("没有需要清理的过期会话")
  44. db.close()
  45. except Exception as e:
  46. logger.exception("Session清理初始化异常")
  47. # 初始化心跳监控
  48. try:
  49. from app.services.heartbeat_monitor import HeartbeatMonitor
  50. cleaned_cache = HeartbeatMonitor.cleanup_cache()
  51. if cleaned_cache > 0:
  52. logger.info(f"清理了 {cleaned_cache} 个过期的缓存条目")
  53. else:
  54. logger.info("心跳缓存状态正常")
  55. except Exception as e:
  56. logger.exception("心跳监控初始化异常")
  57. # 创建FastAPI应用
  58. app = FastAPI(
  59. title="游铛铛API",
  60. description="游铛铛产品后端API",
  61. version="1.0.0",
  62. docs_url="/docs",
  63. redoc_url="/redoc",
  64. lifespan=lifespan_manager,
  65. )
  66. # CORS配置
  67. app.add_middleware(
  68. CORSMiddleware,
  69. allow_origins=["*"], # 生产环境应限制具体域名
  70. allow_credentials=True,
  71. allow_methods=["*"],
  72. allow_headers=["*"],
  73. )
  74. # API日志中间件(使用 ASGI 中间件以可靠捕获响应体)
  75. from app.middleware.auth import AuthValidationASGIMiddleware
  76. from app.middleware.logging import APILoggingASGIMiddleware
  77. # 认证校验中间件先执行,校验 token / 用户 / 卡密
  78. app.add_middleware(AuthValidationASGIMiddleware)
  79. # 然后记录 API 日志(依赖认证信息)
  80. app.add_middleware(APILoggingASGIMiddleware)
  81. # 异常处理
  82. from fastapi import HTTPException
  83. @app.exception_handler(HTTPException)
  84. async def http_exception_handler(request: Request, exc: HTTPException):
  85. """统一处理HTTPException,返回前端期望的格式"""
  86. return JSONResponse(
  87. status_code=exc.status_code,
  88. content={"code": exc.status_code, "msg": exc.detail}
  89. )
  90. @app.exception_handler(BusinessException)
  91. async def business_exception_handler(request: Request, exc: BusinessException):
  92. return JSONResponse(
  93. status_code=200,
  94. content={"code": exc.code, "msg": exc.msg}
  95. )
  96. @app.exception_handler(Exception)
  97. async def general_exception_handler(request: Request, exc: Exception):
  98. logger.error(f"未处理的异常: {exc}", exc_info=True)
  99. return JSONResponse(
  100. status_code=500,
  101. content={"code": 500, "msg": "服务器内部错误"}
  102. )
  103. # 注册路由
  104. app.include_router(client_router, prefix="/api", tags=["客户端接口"])
  105. app.include_router(admin_router, prefix="/admin", tags=["管理端接口"])
  106. @app.get("/")
  107. async def root():
  108. """根路径"""
  109. return {"message": "游铛铛API", "version": "1.0.0"}
  110. @app.get("/health")
  111. async def health():
  112. """健康检查"""
  113. return {"status": "ok"}
  114. if __name__ == "__main__":
  115. import uvicorn
  116. uvicorn.run(app, host="0.0.0.0", port=8000)