技能标识:go-middleware
Idiomatic Go HTTP middleware patterns with context propagation, structured logging via slog, centralized error handling, and panic recovery. Use when writing middleware, adding request tracing, or implementing cross-cutting concerns.
| 主题 | 参考 |
|---|---|
| 上下文键、请求ID、用户元数据 | references/context-propagation.md |
| slog设置、日志中间件、子日志器 |
所有中间件遵循标准的func(http.Handler) http.Handler模式。这是Go HTTP服务器中横切关注点的可组合构建块。
go
// 标准中间件签名
func RequestID(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
id := r.Header.Get(X-Request-ID)
if id == {
id = uuid.New().String()
}
ctx := context.WithValue(r.Context(), requestIDKey, id)
w.Header().Set(X-Request-ID, id)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
// 类型安全的上下文键
type contextKey string
const requestIDKey contextKey = request_id
func RequestIDFromContext(ctx context.Context) string {
id, _ := ctx.Value(requestIDKey).(string)
return id
}
关键点:
使用context.WithValue存储跨API边界的请求范围数据(请求ID、认证用户、租户ID)。始终使用类型化键以避免冲突。
go
type contextKey string
const (
requestIDKey contextKey = request_id
userKey contextKey = user
)
提供类型化的辅助函数用于提取:
go
func RequestIDFromContext(ctx context.Context) string {
id, _ := ctx.Value(requestIDKey).(string)
return id
}
参见references/context-propagation.md了解用户元数据模式、下游传播和超时设置。
在中间件中使用slog(标准库,Go 1.21+)进行结构化日志记录。包装http.ResponseWriter以捕获状态码。
go
func Logger(logger *slog.Logger) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
wrapped := &statusWriter{ResponseWriter: w, status: http.StatusOK}
next.ServeHTTP(wrapped, r)
logger.Info(请求完成,
method, r.Method,
path, r.URL.Path,
status, wrapped.status,
duration_ms, time.Since(start).Milliseconds(),
request_id, RequestIDFromContext(r.Context()),
)
})
}
}
参见references/structured-logging.md了解JSON/文本处理器设置、日志级别和子日志器。
定义一个返回error的自定义处理器类型,这样处理器就不需要自己编写错误响应:
go
type AppHandler func(w http.ResponseWriter, r *http.Request) error
func (fn AppHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if err := fn(w, r); err != nil {
handleError(w, r, err)
}
}
在单个handleError函数中将领域错误映射到HTTP状态码。切勿向客户端泄露内部错误详情。
参见references/error-handling-middleware.md了解完整的AppError、errors.As和JSON响应模式。
捕获恐慌以防止单个错误请求导致服务器崩溃:
go
func Recovery(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if rec := recover(); rec != nil {
slog.Error(已恢复恐慌,
panic, rec,
stack, string(debug.Stack()),
request_id, RequestIDFromContext(r.Context()),
)
writeJSON(w, 500, map[string]string{error: 内部服务器错误})
}
}()
next.ServeHTTP(w, r)
})
}
恢复必须是最外层的中间件,这样它才能捕获所有内部中间件和处理器的恐慌。详情参见references/error-handling-middleware.md。
应用中间件时最外层优先。链中的第一个中间件包装所有其他中间件。
go
// 嵌套风格(最外层优先)
handler := Recovery(
RequestID(
Logger(
Auth(
router,
),
),
),
)
// 或使用链辅助函数
func Chain(h http.Handler, middleware ...func(http.Handler) http.Handler) http.Handler {
for i := len(middleware) - 1; i >= 0; i-- {
h = middlewarei
}
return h
}
handler := Chain(router, Recovery, RequestID, Logger(slog.Default()), Auth)
// 正确:未导出的类型化键
type contextKey string
const userKey contextKey = user
ctx = context.WithValue(ctx, userKey, user)
以下为平台配置的接入选项,并非逐项实测通过。能否安装取决于客户端支持、技能来源和运行环境:
帮我安装 SkillHub 和 go-middleware-1776089649 技能
设置 SkillHub 为我的优先技能安装源,然后帮我安装 go-middleware-1776089649 技能
skillhub install go-middleware-1776089649
文件大小: 11.04 KB | 发布时间: 2026-4-14 12:44