From 7c743293beb727844bb4685c6dc052265db44ea6 Mon Sep 17 00:00:00 2001 From: canglan Date: Wed, 15 Apr 2026 12:36:37 +0800 Subject: [PATCH] =?UTF-8?q?v0.7.2=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../changes/fix-admin-multi-issues/task.md | 9 ++++ backend/main.py | 17 ++++++++ backend/routes/admin.py | 42 +++++++++++-------- backend/routes/student.py | 30 +++++++------ backend/routes/subject.py | 12 ++++-- 5 files changed, 77 insertions(+), 33 deletions(-) diff --git a/.cospec/plan/changes/fix-admin-multi-issues/task.md b/.cospec/plan/changes/fix-admin-multi-issues/task.md index 18407fd..ddf9ee9 100644 --- a/.cospec/plan/changes/fix-admin-multi-issues/task.md +++ b/.cospec/plan/changes/fix-admin-multi-issues/task.md @@ -367,3 +367,12 @@ - auth.py: change_password路由从请求中读取force参数传递给服务层 - dashboard.php: 强制改密请求中添加force:true, old_password设为空字符串 - 科目管理500和管理员管理500: 经代码审查确认代码逻辑正确(SQL、路由、模型均无问题),500错误为后端服务未重启导致旧代码仍在运行 + +- [x] 12.14 添加全局异常处理器 + 4个500路由添加try-except + 历史记录page_size上限修复 + 【目标对象】`backend/main.py`、`backend/routes/subject.py`、`backend/routes/admin.py`、`backend/routes/student.py` + 【修改目的】用户确认后端已重启但仍报500,4个路由持续返回500 Internal Server Error(科目管理、管理员管理、历史记录、学生端操行分)。无法直接查看后端日志,需通过全局异常处理器和路由级try-except捕获具体错误原因 + 【修改方式】 + - main.py: 添加全局异常处理器 global_exception_handler,捕获所有未处理异常,返回包含str(exc)的message和可选的traceback detail(仅DEBUG模式) + - subject.py: get_subjects路由添加try-except,新增logger导入 + - admin.py: get_admins和get_conduct_history路由添加try-except;get_conduct_history的page_size参数le=100→le=1000 + - student.py: get_conduct_history路由添加try-except,新增logger导入 diff --git a/backend/main.py b/backend/main.py index 93ba51b..fb7a7c4 100644 --- a/backend/main.py +++ b/backend/main.py @@ -11,7 +11,9 @@ from fastapi import FastAPI, Request from fastapi.middleware.cors import CORSMiddleware +from fastapi.responses import JSONResponse from contextlib import asynccontextmanager +import traceback import uvicorn from config import settings @@ -78,6 +80,21 @@ app.add_middleware( ) +# 全局异常处理器 +@app.exception_handler(Exception) +async def global_exception_handler(request: Request, exc: Exception): + """全局异常处理器 - 捕获所有未处理异常""" + logger.error(f"未处理异常: {exc}", exc_info=True) + return JSONResponse( + status_code=500, + content={ + "success": False, + "message": f"服务器内部错误: {str(exc)}", + "detail": traceback.format_exc() if settings.DEBUG else None + } + ) + + # 注册路由 app.include_router(auth.router, prefix="/api/auth", tags=["认证"]) app.include_router(student.router, prefix="/api/student", tags=["学生端"]) diff --git a/backend/routes/admin.py b/backend/routes/admin.py index da8effb..b6632e0 100644 --- a/backend/routes/admin.py +++ b/backend/routes/admin.py @@ -176,21 +176,25 @@ async def get_conduct_history( request: Request, student_id: Optional[int] = None, page: int = Query(1, ge=1), - page_size: int = Query(20, ge=1, le=100), + page_size: int = Query(20, ge=1, le=1000), start_date: Optional[str] = None, end_date: Optional[str] = None ): """获取操行分历史记录""" - user = await get_current_user(request) - result = await ConductService.get_history( - user_id=user["user_id"], - student_id=student_id, - page=page, - page_size=page_size, - start_date=start_date, - end_date=end_date - ) - return success_response(data=result) + try: + user = await get_current_user(request) + result = await ConductService.get_history( + user_id=user["user_id"], + student_id=student_id, + page=page, + page_size=page_size, + start_date=start_date, + end_date=end_date + ) + return success_response(data=result) + except Exception as e: + logger.error(f"获取历史记录失败: {e}", exc_info=True) + return error_response(message=f"获取历史记录失败: {str(e)}", code=500) # ========== 作业管理 ========== @@ -360,9 +364,13 @@ async def add_admin(request: Request, req: AddAdminRequest): @router.get("/list") async def get_admins(request: Request): """获取管理员列表(班主任)""" - user = await get_current_user(request) - is_teacher = await PermissionChecker.check_is_teacher(user["user_id"]) - if not is_teacher: - return error_response(message="仅班主任可查看管理员列表", code=403) - result = await AdminService.get_admins() - return success_response(data=result) \ No newline at end of file + try: + user = await get_current_user(request) + is_teacher = await PermissionChecker.check_is_teacher(user["user_id"]) + if not is_teacher: + return error_response(message="仅班主任可查看管理员列表", code=403) + result = await AdminService.get_admins() + return success_response(data=result) + except Exception as e: + logger.error(f"获取管理员列表失败: {e}", exc_info=True) + return error_response(message=f"获取管理员列表失败: {str(e)}", code=500) \ No newline at end of file diff --git a/backend/routes/student.py b/backend/routes/student.py index dc681ea..35a5611 100644 --- a/backend/routes/student.py +++ b/backend/routes/student.py @@ -31,19 +31,23 @@ async def get_conduct_history( """ 获取学生操行分历史 """ - user = await get_current_user(request) - - # 权限检查:只能查看自己的信息(学生)或同班(管理员) - if user["user_type"] == "student" and user["student_id"] != student_id: - return error_response(message="无权查看其他学生信息", code=403) - - result = await StudentService.get_conduct_history( - student_id=student_id, - limit=limit, - offset=offset - ) - - return success_response(data=result) + try: + user = await get_current_user(request) + + # 权限检查:只能查看自己的信息(学生)或同班(管理员) + if user["user_type"] == "student" and user["student_id"] != student_id: + return error_response(message="无权查看其他学生信息", code=403) + + result = await StudentService.get_conduct_history( + student_id=student_id, + limit=limit, + offset=offset + ) + + return success_response(data=result) + except Exception as e: + logger.error(f"获取学生操行分失败: {e}", exc_info=True) + return error_response(message=f"获取学生操行分失败: {str(e)}", code=500) @router.get("/homework/{student_id}") diff --git a/backend/routes/subject.py b/backend/routes/subject.py index 630faba..a4c4b87 100644 --- a/backend/routes/subject.py +++ b/backend/routes/subject.py @@ -15,14 +15,20 @@ from middleware.permission import get_current_user, PermissionChecker from services.subject_service import SubjectService from schemas.subject import CreateSubjectRequest, UpdateSubjectRequest from utils.response import success_response, error_response +from utils.logger import get_logger router = APIRouter() +logger = get_logger(__name__) @router.get("/list") async def get_subjects(request: Request, is_active: Optional[bool] = None): - user = await get_current_user(request) - result = await SubjectService.get_subjects(is_active=is_active) - return success_response(data=result) + try: + user = await get_current_user(request) + result = await SubjectService.get_subjects(is_active=is_active) + return success_response(data=result) + except Exception as e: + logger.error(f"获取科目列表失败: {e}", exc_info=True) + return error_response(message=f"获取科目列表失败: {str(e)}", code=500) @router.post("/create") async def create_subject(request: Request, req: CreateSubjectRequest):