Files
Inbox/Go项目实战/中间件/推荐的中间件目录演进策略.md

81 lines
3.1 KiB
Markdown
Raw Normal View History

2025-12-11 07:24:36 +08:00
---
tags: []
aliases:
- 🏗️ 推荐的中间件目录演进策略
date created: 星期三, 十二月 10日 2025, 11:08:17 上午
date modified: 星期三, 十二月 10日 2025, 11:08:58 上午
---
这是一个非常有前瞻性的问题。你现在的顾虑完全符合 **“高内聚、低耦合”** 的架构直觉。
在企业级 Go 项目中如果把所有中间件Auth, CORS, RateLimit, Logger, Recovery, Trace…都堆在 `internal/middleware/` 根目录下,确实会变成一个“大杂烩”,导致文件结构不明晰。
基于 **Modular Clean Architecture****Go 最佳实践**,我推荐采用 **“按复杂度分层 (Complexity-Based Layering)”** 的混合策略。
# 🏗️ 推荐的中间件目录演进策略
我们不需要一开始就过度设计Over-engineering而是制定一条**规则**
1. **通用基础设施 (Universal Infra):** 逻辑简单、无状态、单文件即可解决的,直接放在根目录。
2. **复杂业务逻辑 (Complex Logic):** 需要定义配置结构体、辅助函数、或依赖外部库较重的,**建立子目录**。
## 修正后的目录蓝图
```Plaintext
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 里的调用通常希望长这样:
```Go
// 读起来很通顺:使用中间件 -> 恢复、日志、CORS
r.Use(middleware.Recovery())
r.Use(middleware.Logger())
r.Use(middleware.Cors())
```
如果强行把 `recovery.go` 放到 `middleware/recovery/recovery.go`,调用就会变成 `recovery.New()`,这在语义上丢失了“这是一个中间件”的上下文,而且引入了太多的包名。
- 对于复杂中间件:
认证通常需要配置:
```Go
// 读起来清楚:这是 Auth 相关的中间件
r.Use(auth.Middleware(auth.Config{…}))
```
这时候引入 `auth` 子包是合理的。
## 2. 避免循环依赖
`recovery.go``not_found.go` 属于**基础设施的底座**,它们几乎不依赖其他业务代码(除了我们刚才定义的 `app` 包)。将它们放在根目录,可以方便地被其他子包引用(虽然中间件之间很少互相引用)。
---