"""统一响应与业务异常(对齐《03-接口文档》1.2 统一响应结构)""" import uuid from contextvars import ContextVar from typing import Any from fastapi import FastAPI, Request from fastapi.exceptions import RequestValidationError from fastapi.responses import JSONResponse from app.core import errors # 请求链路 ID(中间件写入,日志/响应共用) request_id_ctx: ContextVar[str] = ContextVar("request_id", default="") def ok(data: Any = None, message: str = "ok") -> dict: return { "code": errors.OK, "message": message, "data": data if data is not None else {}, "request_id": request_id_ctx.get() or str(uuid.uuid4()), } class BizException(Exception): """业务异常:抛出后由全局处理器转为统一响应""" def __init__(self, code: int, message: str | None = None, http_status: int = 200, data: dict | None = None): self.code = code self.message = message or errors.DEFAULT_MESSAGES.get(code, "error") self.http_status = http_status self.data = data or {} def _fail_body(code: int, message: str, data: dict | None = None) -> dict: return { "code": code, "message": message, "data": data or {}, "request_id": request_id_ctx.get() or str(uuid.uuid4()), } def register_exception_handlers(app: FastAPI) -> None: @app.exception_handler(BizException) async def biz_handler(request: Request, exc: BizException) -> JSONResponse: return JSONResponse(status_code=exc.http_status, content=_fail_body(exc.code, exc.message, exc.data)) @app.exception_handler(RequestValidationError) async def validation_handler(request: Request, exc: RequestValidationError) -> JSONResponse: return JSONResponse( status_code=200, content=_fail_body(errors.PARAM_ERROR, f"参数错误: {exc.errors()[0].get('msg', '')}"), ) @app.exception_handler(Exception) async def unhandled_handler(request: Request, exc: Exception) -> JSONResponse: return JSONResponse(status_code=500, content=_fail_body(errors.INTERNAL_ERROR, "服务器内部错误"))