跳转到内容

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))
  • 你正在新增或调整 func(http.Handler) http.Handler 形态的行为
  • 工作围绕顺序敏感的 HTTP transport concern
  • 改动是在做请求观测,但不拥有 tenant 或产品策略
  • 行为已经变成业务校验、tenant resolution 或 tenant quota policy
  • 任务真正是 API version negotiation 或协议转换
  • 工作本质上是应用构造,而不是 transport wrapper
  1. middleware/module.yaml
  2. docs/reference/canonical-style-guide.md
  3. middleware/* 下的目标包
这些工作适合留在 middleware一旦变成这些问题就应移出
request ID、tracing hook、access logging 与 HTTP metricsx/observability 中更高层的 observability adapter 与 export wiring
建立在 security/* 原语之上的 auth 与 security-header HTTP adapterx/tenant 中的 tenant policy 与 tenant resolution
建立在稳定 abuse-guard 原语之上的薄 rate-limit adapterlimiter implementation catalog 或能力特定 quota 行为
基于显式 constructor 的 HTTP wrapperx/rest/versioning 中的 API version negotiation,或 x/gateway/* 中的协议适配
app.Use(mw1, mw2, mw3) // 按注册顺序执行,最外层最先运行

Use 必须在 app.Prepare() 之前调用。

所有包位于 github.com/spcent/plumego/middleware/ 下。

构造函数作用
requestidrequestid.Middleware()生成或透传唯一请求 ID;存入 context
recoveryrecovery.Middleware(recovery.Config{Logger: logger})捕获 panic,记录脱敏 panic 元数据,返回 500
accesslogaccesslog.Middleware(accesslog.Config{Logger: logger})为每个请求记录方法、路径、状态码和耗时
authauthmw.Authenticate(authenticator)构造时校验认证依赖;认证失败返回 401
securitysecmw.Middleware(secmw.Config{Policy: policy})设置 CSP、X-Frame-Options、HSTS 等安全头
corscors.Middleware(opts)处理预检请求并添加 CORS 响应头
timeouttimeout.Middleware(cfg)超时后取消请求 context,返回 504
ratelimitratelimit.AbuseGuard(cfg)令牌桶限流;超限返回 429 + Retry-After
bodylimitbodylimit.BodyLimit(maxBytes, logger)请求体超过限制时返回 413
compressioncompression.Middleware(cfg)为支持 gzip 的客户端压缩响应
httpmetricshttpmetrics.Middleware(observer)记录请求数、状态分布和延迟
tracingtracing.Middleware(tracer)注入或传播分布式追踪 context
concurrencylimitconcurrencylimit.Middleware(max, queue, timeout)限制并发请求数;超出队列深度时返回 503
debugdebug.Middleware(cfg)开发模式错误捕获,不要在生产环境使用
coalescecoalesce.New(cfg).Middleware()请求合并——对相同并发请求去重,共用一个响应
conformanceconformance.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)

任何 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))

middleware 很容易因为”都发生在请求路径上”而被越写越胖。当前仓库刻意把这条线压得很窄:只要行为不再是 transport-only,稳定 middleware 层就已经不是正确归属。