Files
Inbox/Go项目实战/中间件/推荐的中间件目录演进策略.md
2025-12-11 07:24:36 +08:00

3.1 KiB
Raw Permalink Blame History

tags, aliases, date created, date modified
tags aliases date created date modified
🏗️ 推荐的中间件目录演进策略
星期三, 十二月 10日 2025, 11:08:17 上午 星期三, 十二月 10日 2025, 11:08:58 上午

这是一个非常有前瞻性的问题。你现在的顾虑完全符合 “高内聚、低耦合” 的架构直觉。

在企业级 Go 项目中如果把所有中间件Auth, CORS, RateLimit, Logger, Recovery, Trace…都堆在 internal/middleware/ 根目录下,确实会变成一个“大杂烩”,导致文件结构不明晰。

基于 Modular Clean ArchitectureGo 最佳实践,我推荐采用 “按复杂度分层 (Complexity-Based Layering)” 的混合策略。

🏗️ 推荐的中间件目录演进策略

我们不需要一开始就过度设计Over-engineering而是制定一条规则

  1. 通用基础设施 (Universal Infra): 逻辑简单、无状态、单文件即可解决的,直接放在根目录。
  2. 复杂业务逻辑 (Complex Logic): 需要定义配置结构体、辅助函数、或依赖外部库较重的,建立子目录

修正后的目录蓝图

internal/
└── middleware/
    │
    │   # --- Level 1: 通用基础设施 (直接放根目录) ---
    ├── recovery.go        # [现有] 及其简单,就一个函数
    ├── not_found.go       # [现有] 就一个 Handler
    ├── cors.go            # [未来] CORS 配置通常单文件搞定
    ├── trace.go           # [未来] 注入 TraceID
    │
    │   # --- Level 2: 复杂中间件 (独立子包) ---
    ├── auth/              # [未来] 认证模块很复杂
    │   ├── jwt.go         # JWT 解析逻辑
    │   └── context.go     # 将 UserID 注入 Context 的辅助函数
    │
    ├── ratelimit/         # [未来] 限流可能涉及 Redis 脚本
    │   ├── ip_limiter.go
    │   └── lua_script.go
    │
    └── log/               # [未来] 访问日志
        └── access_logger.go

💡 为什么要这样设计?(Rationale)

1. Go 的包导入体验 (Import DX)

  • 对于通用中间件:

    我们在 main.go 里的调用通常希望长这样:

    // 读起来很通顺:使用中间件 -> 恢复、日志、CORS
    r.Use(middleware.Recovery())
    r.Use(middleware.Logger())
    r.Use(middleware.Cors())
    

    如果强行把 recovery.go 放到 middleware/recovery/recovery.go,调用就会变成 recovery.New(),这在语义上丢失了“这是一个中间件”的上下文,而且引入了太多的包名。

  • 对于复杂中间件:

    认证通常需要配置:

    // 读起来清楚:这是 Auth 相关的中间件
    r.Use(auth.Middleware(auth.Config{}))
    

    这时候引入 auth 子包是合理的。

2. 避免循环依赖

recovery.gonot_found.go 属于基础设施的底座,它们几乎不依赖其他业务代码(除了我们刚才定义的 app 包)。将它们放在根目录,可以方便地被其他子包引用(虽然中间件之间很少互相引用)。