Files
012-kaopeilian/backend/app/main.py
111 998211c483 feat: 初始化考培练系统项目
- 从服务器拉取完整代码
- 按框架规范整理项目结构
- 配置 Drone CI 测试环境部署
- 包含后端(FastAPI)、前端(Vue3)、管理端

技术栈: Vue3 + TypeScript + FastAPI + MySQL
2026-01-24 19:33:28 +08:00

141 lines
3.4 KiB
Python

"""考培练系统后端主应用"""
import logging
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from fastapi.staticfiles import StaticFiles
import json
import os
from app.core.config import get_settings
from app.api.v1 import api_router
# 配置日志
logging.basicConfig(
level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger(__name__)
settings = get_settings()
@asynccontextmanager
async def lifespan(app: FastAPI):
"""应用生命周期管理"""
# 启动时执行
logger.info(f"启动 {settings.APP_NAME} v{settings.APP_VERSION}")
# 初始化 Redis
try:
from app.core.redis import init_redis, close_redis
await init_redis()
logger.info("Redis 初始化成功")
except Exception as e:
logger.warning(f"Redis 初始化失败(非致命): {e}")
yield
# 关闭时执行
try:
from app.core.redis import close_redis
await close_redis()
logger.info("Redis 连接已关闭")
except Exception as e:
logger.warning(f"关闭 Redis 连接失败: {e}")
logger.info("应用关闭")
# 自定义 JSON 响应类,确保中文正确编码
class UTF8JSONResponse(JSONResponse):
def render(self, content) -> bytes:
return json.dumps(
content,
ensure_ascii=False,
allow_nan=False,
indent=None,
separators=(",", ":"),
).encode("utf-8")
# 创建FastAPI应用
app = FastAPI(
title=settings.APP_NAME,
version=settings.APP_VERSION,
description="考培练系统后端API",
lifespan=lifespan,
# 确保响应正确的 UTF-8 编码
default_response_class=UTF8JSONResponse,
)
# 配置CORS
app.add_middleware(
CORSMiddleware,
allow_origins=settings.CORS_ORIGINS,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# 健康检查端点
@app.get("/health")
async def health_check():
"""健康检查"""
return {
"status": "healthy",
"service": settings.APP_NAME,
"version": settings.APP_VERSION,
}
# 根路径
@app.get("/")
async def root():
"""根路径"""
return {
"message": f"欢迎使用{settings.APP_NAME}",
"version": settings.APP_VERSION,
"docs": "/docs",
}
# 注册路由
app.include_router(api_router, prefix="/api/v1")
# 挂载静态文件目录
# 创建上传目录(如果不存在)
upload_path = settings.UPLOAD_PATH
os.makedirs(upload_path, exist_ok=True)
# 挂载上传文件目录为静态文件服务
app.mount("/static/uploads", StaticFiles(directory=upload_path), name="uploads")
# 全局异常处理
@app.exception_handler(Exception)
async def global_exception_handler(request, exc):
"""全局异常处理"""
logger.error(f"未处理的异常: {exc}", exc_info=True)
return JSONResponse(
status_code=500,
content={
"code": 500,
"message": "内部服务器错误",
"detail": str(exc) if settings.DEBUG else None,
},
)
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(),
)
# 测试热重载 - Fri Sep 26 03:37:07 CST 2025