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

81 lines
3.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
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` 包)。将它们放在根目录,可以方便地被其他子包引用(虽然中间件之间很少互相引用)。
---