Files
DjangoAdmin_FastAPI_EleVue/core/app.py
T
ClaudeandClaude 63bebedf05 feat(phase5): 解耦与收尾清理
- core/redis_client.py 移除 scheduler 耦合,lifespan 由 core/app.py 组合(Redis→调度器→Redis)
- main.py 改从 core.app 导入 create_app
- 删除 apps/、extensions/ 目录;utils 删除已迁移垫片与死代码 formatter.py
- 新增 deploy/(nginx、supervisor)、scripts/(init_db、seed)、logs/(结构化日志落盘)
- core/app.py 接入 core.logger setup_logging
- 更新 CLAUDE.md 反映 core/shared/modules 新结构

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-07 10:16:44 +08:00

122 lines
4.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# +======================================================================
# | DjangoAdmin 企业数字化开发平台 [ 赋能开发者,助力企业发展 ]
# +----------------------------------------------------------------------
# | Copyright (c) 2021-2026 一米阳光团队 版权所有
# | 开源协议: Apache-2.0
# +======================================================================
# 由 apps/__init__.py 迁移而来。
"""应用工厂:create_app 组装中间件、路由、异常处理与 lifespan。"""
import logging
import time
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.exceptions import RequestValidationError
from fastapi.logger import logger
from starlette.requests import Request
from starlette.responses import JSONResponse
from config.app import FASTAPI_DEBUG
from core.exceptions import AuthorizationException, BusinessException
from core.logger import setup_logging
from core.middleware import (
register_middleware,
register_cros,
db_session_middleware,
operation_log_middleware,
)
from core.redis_client import redis_lifespan, redis_middleware
from routers import register_router
@asynccontextmanager
async def _combined_lifespan(app: FastAPI):
"""组合 lifespan:先起 Redis,再启动定时任务调度器;退出时先停调度器再关 Redis。"""
async with redis_lifespan(app):
# 懒加载调度器,避免 core → 业务模块顶层依赖
from modules.job.scheduler import init_scheduler, shutdown_scheduler
job_count = init_scheduler()
logging.getLogger(__name__).info(
f"定时任务调度器已启动,加载 {job_count} 个任务")
try:
yield
finally:
shutdown_scheduler()
def create_app() -> FastAPI:
# 初始化结构化日志(控制台 + logs/app.log)
setup_logging()
app = FastAPI(
title="FastAPI",
description="FastAPI",
version="v1",
lifespan=_combined_lifespan,
)
# 注册跨域中间件
register_cros(app)
# 注册Redis上下文注入中间件(先注册→内层:先注入Redis再开DB会话)
app.middleware("http")(redis_middleware)
# 注册数据库会话中间件(后注册→外层:DB会话包裹业务逻辑,finally保证关闭)
app.middleware("http")(db_session_middleware)
# 注册操作日志中间件(在DB会话内层,记录写操作日志)
app.middleware("http")(operation_log_middleware)
# 注册路由
register_router(app)
# 登录检测
register_middleware(app)
# 注册全局异常处理
register_exception(app)
# 请求计时(最后注册→最外层,统计完整耗时)
@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
response.headers["X-Process-Time"] = str(round(process_time, 5))
if FASTAPI_DEBUG:
logger.info(f"访问记录:{request.method} url:{request.url} 耗时:{str(round(process_time, 5))}")
return response
return app
# 注册全局异常处理
def register_exception(app: FastAPI):
"""全局异常捕获。"""
@app.exception_handler(AuthorizationException)
async def unicorn_exception_handler(request: Request, exc: AuthorizationException):
return JSONResponse(
status_code=200,
content={"code": exc.code, "data": None, "msg": exc.msg, "ok": False},
)
@app.exception_handler(BusinessException)
async def business_exception_handler(request: Request, exc: BusinessException):
return JSONResponse(
status_code=200,
content={"code": exc.code, "data": None, "msg": exc.msg, "ok": False},
)
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
errors = []
for err in exc.errors():
field = err.get("loc", [""])[-1]
msg = err.get("msg", "")
if field and field != "body":
errors.append(f"{field}: {msg}")
else:
errors.append(msg)
return JSONResponse(
status_code=200,
content={"code": 1, "data": None, "msg": "/".join(errors)},
)