## Context 当前 API 服务基于 Gin 构建。本次任务的目标是将其完整迁移到 Echo 框架,同时保持功能和接口的完全向后兼容。这包括路由、请求处理、中间件、Swagger 文档和 pprof 分析工具。 ## Goals / Non-Goals - **Goals**: - 成功将 Web 框架从 Gin 迁移到 Echo v4。 - 保持所有现有 API 端点的路径、方法和行为不变。 - 确保所有自定义中间件(认证、审计日志)功能正常。 - 确保 Swagger UI 可以在 `/swagger/index.html` 正常访问。 - 确保 pprof 调试端点在 `/debug/pprof/*` 路径下正常工作。 - **Non-Goals**: - 增加任何新的 API 端点或功能。 - 修改任何现有的 API 请求/响应模型。 - 在本次变更中引入新的业务逻辑。 ## Decisions 以下是从 Gin 到 Echo 的关键组件映射决策: 1. **框架实例**: - **From**: `gin.SetMode(cfg.Mode)`, `engine := gin.New()`, `engine.Use(gin.Recovery())` - **To**: `e := echo.New()`, `e.Debug = (cfg.Mode == "debug")`, `e.Use(middleware.Recover())` - **Rationale**: `echo.New()` 提供了干净的实例。Echo 的 `Debug` 属性控制调试模式,可以根据配置设置。Echo 提供了内置的 `middleware.Recover()` 来替代 Gin 的 Recovery 中间件。 - **Implementation**: - 在 `internal/app/api/api.go` 中,将 `engine *gin.Engine` 替换为 `engine *echo.Echo`,并更新 `NewAPI` 方法中的初始化逻辑。 - 在 `config.yml` 和 `config.example.yml` 中, 更新关于 `mode` 配置项的注释, 将 "Gin 运行模式" 修改为 "服务运行模式", 因为该配置项现在控制 Echo 的调试模式。 2. **上下文对象 (Context) 与处理器签名**: - **From**: `func(c *gin.Context)` - **To**: `func(c echo.Context) error` - **Rationale**: 这是两个框架的核心区别。所有控制器处理函数签名都需要更新。常见方法映射如下: - `ctx.ShouldBindJSON(&req)` -> `c.Bind(&req)` (Echo 的 `Bind` 更通用,能根据 `Content-Type` 自动选择解析器) - `ctx.ShouldBindQuery(&req)` -> `c.Bind(&req)` - `ctx.Param("id")` -> `c.Param("id")` (签名相同) - `ctx.GetHeader("Authorization")` -> `c.Request().Header.Get("Authorization")` - `ctx.Set("key", value)` -> `c.Set("key", value)` (签名相同) - `ctx.Get("key")` -> `c.Get("key")` (签名相同) - `ctx.ClientIP()` -> `c.RealIP()` - `controller.SendResponse(ctx, ...)` -> `return controller.SendResponse(c, ...)` (控制器方法需要返回 `error`,辅助函数也需要修改以返回 `error`) - `controller.SendErrorResponse(ctx, ...)` -> `return controller.SendErrorResponse(c, ...)` (同上) - `ctx.AbortWithStatusJSON(...)` -> `return c.JSON(...)` (在中间件中,通过 `return c.JSON(...)` 来中断链并响应) 3. **中间件 (Middleware)**: - **From**: `func AuthMiddleware(...) gin.HandlerFunc { return func(c *gin.Context) { ... } }` - **To**: `func AuthMiddleware(...) echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { ...; return next(c) } } }` - **Rationale**: Echo 的中间件是一个包装器模式。我们需要将现有的 `AuthMiddleware` 和 `AuditLogMiddleware` 逻辑迁移到这个新的结构中。中断请求链的方式从 `c.AbortWithStatusJSON()` 变为从处理函数中 `return c.JSON(...)`。 4. **Swagger 集成**: - **From**: `github.com/swaggo/gin-swagger` - **To**: `github.com/swaggo/echo-swagger` - **Rationale**: 这是 `swaggo` 官方为 Echo 提供的适配库,可以无缝替换。 - **Implementation**: 在 `router.go` 中使用 `e.GET("/swagger/*", echoSwagger.WrapHandler)`。 5. **Pprof 与其他 `net/http` 处理器集成**: - **From**: `gin.WrapH` 和 `gin.WrapF` - **To**: `echo.WrapHandler` 和 `echo.WrapFunc` - **Rationale**: Echo 提供了类似的 `net/http` 处理器包装函数,可以轻松集成 pprof 和项目中的 `listenHandler`。 - **Implementation**: 在 `router.go` 中替换所有 `gin.WrapH` 和 `gin.WrapF` 的调用。 6. **控制器辅助函数**: - **Affected Files**: - `internal/app/controller/response.go` - `internal/app/controller/auth_utils.go` - `internal/app/controller/management/controller_helpers.go` - **Change**: - 在 `response.go` 和 `auth_utils.go` 中, 所有接收 `*gin.Context` 的辅助函数 (如 `SendResponse`, `GetOperatorIDFromContext` 等) 签名都需要修改为接收 `echo.Context`。 - 在 `controller_helpers.go` 中, `handle...` 系列的泛型辅助函数 (如 `handleAPIRequest`, `handleNoBodyAPIRequest` 等) 及其依赖的 `extractOperatorAndPrimaryID` 和 `mapAndSendError` 函数, 都需要将其中的 `*gin.Context` 参数和相关调用 (如 `ShouldBindJSON`) 替换为 `echo.Context` 的等效实现。 - 所有这些辅助函数, 如果它们原本不返回 `error`, 现在需要修改为返回 `error`, 以便与 Echo 的处理器错误链兼容。例如, `SendResponse` 这类函数在调用 `c.JSON(...)` 后, 最终应 `return nil`。 - **Rationale**: 这些辅助函数封装了请求处理、响应发送和错误处理的核心逻辑, 必须进行适配以兼容 Echo 的 `echo.Context` 上下文对象和 `return error` 的错误处理模式。 ## Risks / Trade-offs - **Risk**: 迁移工作量大,可能遗漏某些 Gin 特有的功能或上下文用法,导致运行时错误。 - **Mitigation**: 采用逐个文件、逐个控制器修改的方式,每修改完一部分就进行编译检查。在完成所有编码后,进行全面的手动 API 测试。 - **Risk**: `AuditLogMiddleware` 中间件依赖 `bodyLogWriter` 捕获响应体,需要验证其与 Echo 的 `ResponseWriter` 是否兼容或需要寻找替代方案。 - **Mitigation**: 在迁移中间件时,优先研究 Echo 官方推荐的 Body Dump 或类似中间件,如果不适用,再尝试适配 `bodyLogWriter`。