Middleware Primer
Middleware Primer
Section titled “Middleware Primer”当你已经通过 稳定根 确认改动仍属于稳定表面,但问题进一步收窄到 transport-only HTTP middleware 时,就打开这一页。
middleware 拥有 request/response wrapper、顺序敏感的 transport 行为,以及那些仍然独立于业务策略的请求观测行为。
app.Use(requestid.Middleware())app.Use(recovery.Recovery(logger))app.Use(accesslog.Middleware(logger))什么时候从这里开始
Section titled “什么时候从这里开始”- 你正在新增或调整
func(http.Handler) http.Handler形态的行为 - 工作围绕顺序敏感的 HTTP transport concern
- 改动是在做请求观测,但不拥有 tenant 或产品策略
什么时候不该从这里开始
Section titled “什么时候不该从这里开始”- 行为已经变成业务校验、tenant resolution 或 tenant quota policy
- 任务真正是 API version negotiation 或协议转换
- 工作本质上是应用构造,而不是 transport wrapper
当前仓库里先读哪些文件
Section titled “当前仓库里先读哪些文件”middleware/module.yamldocs/reference/canonical-style-guide.mdmiddleware/*下的目标包
更具体的归属例子
Section titled “更具体的归属例子”这些工作适合留在 middleware | 一旦变成这些问题就应移出 |
|---|---|
| request ID、tracing hook、access logging 与 HTTP metrics | x/observability 中更高层的 observability adapter 与 export wiring |
建立在 security/* 原语之上的 auth 与 security-header HTTP adapter | x/tenant 中的 tenant policy 与 tenant resolution |
| 建立在稳定 abuse-guard 原语之上的薄 rate-limit adapter | limiter implementation catalog 或能力特定 quota 行为 |
| 基于显式 constructor 的 HTTP wrapper | x/rest/versioning 中的 API version negotiation,或 x/gateway/* 中的协议适配 |
app.Use(mw1, mw2, mw3) // 按注册顺序执行,最外层最先运行Use 必须在 app.Prepare() 之前调用。
内置中间件目录
Section titled “内置中间件目录”所有包位于 github.com/spcent/plumego/middleware/ 下。
| 包 | 构造函数 | 作用 |
|---|---|---|
requestid | requestid.Middleware() | 生成或透传唯一请求 ID;存入 context |
recovery | recovery.Middleware(recovery.Config{Logger: logger}) | 捕获 panic,记录脱敏 panic 元数据,返回 500 |
accesslog | accesslog.Middleware(accesslog.Config{Logger: logger}) | 为每个请求记录方法、路径、状态码和耗时 |
auth | authmw.Authenticate(authenticator) | 构造时校验认证依赖;认证失败返回 401 |
security | secmw.Middleware(secmw.Config{Policy: policy}) | 设置 CSP、X-Frame-Options、HSTS 等安全头 |
cors | cors.Middleware(opts) | 处理预检请求并添加 CORS 响应头 |
timeout | timeout.Middleware(cfg) | 超时后取消请求 context,返回 504 |
ratelimit | ratelimit.AbuseGuard(cfg) | 令牌桶限流;超限返回 429 + Retry-After |
bodylimit | bodylimit.BodyLimit(maxBytes, logger) | 请求体超过限制时返回 413 |
compression | compression.Middleware(cfg) | 为支持 gzip 的客户端压缩响应 |
httpmetrics | httpmetrics.Middleware(observer) | 记录请求数、状态分布和延迟 |
tracing | tracing.Middleware(tracer) | 注入或传播分布式追踪 context |
concurrencylimit | concurrencylimit.Middleware(max, queue, timeout) | 限制并发请求数;超出队列深度时返回 503 |
debug | debug.Middleware(cfg) | 开发模式错误捕获,不要在生产环境使用 |
coalesce | coalesce.New(cfg).Middleware() | 请求合并——对相同并发请求去重,共用一个响应 |
conformance | conformance.Middleware(...) | 按声明契约校验请求/响应合规性 |
来自参考服务的标准顺序:
import ( "github.com/spcent/plumego/middleware/requestid" "github.com/spcent/plumego/middleware/recovery" "github.com/spcent/plumego/middleware/accesslog")
app.Use(requestid.Middleware())recoveryMw, err := recovery.Middleware(recovery.Config{Logger: app.Logger()})if err != nil { return err}app.Use(recoveryMw)accesslogMw, err := accesslog.Middleware(accesslog.Config{Logger: app.Logger()})if err != nil { return err}app.Use(accesslogMw)按需添加 CORS、限流、超时和认证:
app.Use(cors.Middleware(cors.CORSOptions{AllowedOrigins: []string{"https://myapp.com"}}))app.Use(rateLimitMiddleware)app.Use(to.Middleware(to.Config{Timeout: 10 * time.Second}))authMw, err := authmw.Authenticate(jwtManager.Authenticator(jwt.TokenTypeAccess))if err != nil { return err}app.Use(authMw)自定义中间件
Section titled “自定义中间件”任何 func(http.Handler) http.Handler 都是合法的中间件:
func MyMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // 前处理 next.ServeHTTP(w, r) // 后处理 })}
app.Use(middleware.Middleware(MyMiddleware))为什么单独写这一页
Section titled “为什么单独写这一页”middleware 很容易因为”都发生在请求路径上”而被越写越胖。当前仓库刻意把这条线压得很窄:只要行为不再是 transport-only,稳定 middleware 层就已经不是正确归属。
- core API 快速参考 —
App.Use签名及中间件生命周期规则 - 中间件模型
- 自定义中间件指南
- Store Primer
- x/rest Primer
- x/messaging Primer