""" FastAPI应用服务器 整合所有路由和中间件 """ import sys import os # 导入路径配置 try: import path_config # 自动配置 Python 路径 except ImportError: # 手动配置路径(兼容性) sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../..')) sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../../..')) 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 datetime import datetime, timezone import logging import logging.handlers # 导入配置 from app.core.config import config_handler from app.base import init_db, close_db, init_redis, close_redis from app.core.exceptions import BaseAPIException from app.schemas.base import ResponseSchema from app.logger.config import configure_logging, get_logger # 配置全局日志(在导入其他模块之前) configure_logging( log_level=config_handler.get("admin_app", "LOG_LEVEL", "INFO").lower(), log_dir="logs", log_to_file=True, log_to_console=True ) # 获取logger logger = get_logger("lqadmin_server") # 导入视图路由 from views.system_view import router as system_router from views.oauth_view import router as oauth_router from views.sample_view import router as sample_router from views.auth_view import router as auth_router from views.knowledge_base_view import router as knowledge_base_router from views.snippet_view import router as snippet_router # 导入现有API路由 from app.api.v1.api_router import api_router @asynccontextmanager async def lifespan(app: FastAPI): """应用生命周期管理""" # 启动时执行 logger.info("=" * 60) logger.info("正在启动 LQAdminPlatform 服务...") logger.info("=" * 60) try: # 初始化数据库 await init_db() logger.info("✅ 数据库初始化成功") except Exception as e: logger.error(f"❌ 数据库初始化失败: {e}") try: # 初始化Redis await init_redis() logger.info("✅ Redis初始化成功") except Exception as e: logger.warning(f"⚠️ Redis初始化失败: {e}") logger.info("=" * 60) logger.info(f"🚀 服务启动成功!") logger.info(f"📍 服务地址: http://{config_handler.get('admin_app', 'HOST', '0.0.0.0')}:{config_handler.get_int('admin_app', 'PORT', 8000)}") logger.info(f"📚 API文档: http://{config_handler.get('admin_app', 'HOST', '0.0.0.0')}:{config_handler.get_int('admin_app', 'PORT', 8000)}/docs") logger.info("=" * 60) yield # 关闭时执行 logger.info("=" * 60) logger.info("正在关闭 LQAdminPlatform 服务...") logger.info("=" * 60) try: await close_db() logger.info("✅ 数据库连接已关闭") except Exception as e: logger.error(f"❌ 关闭数据库连接失败: {e}") try: await close_redis() logger.info("✅ Redis连接已关闭") except Exception as e: logger.warning(f"⚠️ 关闭Redis连接失败: {e}") logger.info("=" * 60) logger.info("👋 服务已关闭") logger.info("=" * 60) # 创建FastAPI应用实例 app = FastAPI( title=config_handler.get("admin_app", "APP_NAME", "后台管理"), version=config_handler.get("admin_app", "APP_VERSION", "1.0.0"), description="OAuth2单点登录认证中心 - 统一管理平台", docs_url="/docs" if config_handler.get_bool("admin_app", "DEBUG", False) else None, redoc_url="/redoc" if config_handler.get_bool("admin_app", "DEBUG", False) else None, lifespan=lifespan ) # 配置CORS - 允许前端跨域访问 app.add_middleware( CORSMiddleware, allow_origins=[ "http://localhost:8000", "http://localhost:3000", "http://localhost:3001", "http://localhost:5173", # Vite默认端口 "http://localhost:8080", "http://127.0.0.1:3000", "http://127.0.0.1:3001", "http://127.0.0.1:5173", "http://127.0.0.1:8080", "*" # 临时允许所有,方便调试 ], allow_credentials=True, allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"], allow_headers=["*"], ) # --- 调试中间件 --- @app.middleware("http") async def log_requests(request: Request, call_next): # logger.info(f"收到请求: {request.method} {request.url}") try: response = await call_next(request) # logger.info(f"请求响应: {response.status_code}") return response except Exception as e: logger.error(f"请求处理异常: {e}") raise # ------------------ # 全局异常处理 @app.exception_handler(BaseAPIException) async def api_exception_handler(request: Request, exc: BaseAPIException): """处理自定义API异常""" logger.error(f"API异常: {exc.message} - {exc.details}") return JSONResponse( status_code=exc.status_code, content=ResponseSchema( code=exc.code, message=exc.message, data=exc.details, timestamp=datetime.now(timezone.utc) ).model_dump(mode='json') ) @app.exception_handler(RequestValidationError) async def validation_exception_handler(request: Request, exc: RequestValidationError): """处理请求验证异常""" errors = [] for error in exc.errors(): errors.append({ "field": ".".join(str(loc) for loc in error["loc"]), "message": error["msg"], "type": error["type"] }) logger.warning(f"参数验证失败: {errors}") return JSONResponse( status_code=status.HTTP_400_BAD_REQUEST, content=ResponseSchema( code=100001, message="参数验证失败", data={"errors": errors}, timestamp=datetime.now(timezone.utc) ).model_dump(mode='json') ) @app.exception_handler(Exception) async def general_exception_handler(request: Request, exc: Exception): """处理通用异常""" logger.error(f"未处理的异常: {exc}", exc_info=True) return JSONResponse( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=ResponseSchema( code=500001, message="服务器内部错误" if not config_handler.get_bool("admin_app", "DEBUG", False) else str(exc), data=None, timestamp=datetime.now(timezone.utc) ).model_dump(mode='json') ) # 健康检查端点 @app.get("/health", tags=["系统"]) async def health_check(): """健康检查""" return ResponseSchema( code=0, message="服务正常运行", data={ "status": "healthy", "version": config_handler.get("admin_app", "APP_VERSION", "1.0.0"), "timestamp": datetime.now(timezone.utc) } ) # 根路径 @app.get("/", tags=["系统"]) async def root(): """根路径""" return ResponseSchema( code=0, message="欢迎使用 LQAdminPlatform", data={ "name": config_handler.get("admin_app", "APP_NAME", "后台管理"), "version": config_handler.get("admin_app", "APP_VERSION", "1.0.0"), "docs": "/docs" if config_handler.get_bool("admin_app", "DEBUG", False) else None, "modules": ["系统管理", "授权管理", "样本中心"] } ) # 包含API路由 # 现有的API路由(保持兼容) app.include_router(api_router, prefix="/api/v1") # 新的模块化视图路由 app.include_router(system_router, prefix="/api/v1") app.include_router(oauth_router, prefix="") app.include_router(auth_router, prefix="/api/v1") app.include_router(sample_router, prefix="/api/v1") app.include_router(knowledge_base_router, prefix="/api/v1") app.include_router(snippet_router, prefix="/api/v1") def create_app() -> FastAPI: """创建并返回FastAPI应用实例""" return app if __name__ == "__main__": import uvicorn # 查找可用端口 import socket def check_port(port): """检查端口是否可用""" with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: try: s.bind(('localhost', port)) return True except OSError: return False def find_available_port(start_port=8000, max_port=8010): """查找可用端口""" for port in range(start_port, max_port + 1): if check_port(port): return port return None # 获取配置的端口或查找可用端口 port = config_handler.get_int("admin_app", "PORT", 8000) if not check_port(port): logger.warning(f"端口 {port} 已被占用,正在查找可用端口...") port = find_available_port(port, port + 10) if port: logger.info(f"找到可用端口: {port}") else: logger.error("未找到可用端口") sys.exit(1) # 启动服务器 uvicorn.run( "app.server.app:app", host=config_handler.get("admin_app", "HOST", "0.0.0.0"), port=port, reload=config_handler.get_bool("admin_app", "RELOAD", False), log_level=config_handler.get("admin_app", "LOG_LEVEL", "INFO").lower() )