如何使用Golang中间件处理请求_统一日志和认证

9次阅读

go Web中间件通过函数链式包装实现横切关注点处理,如日志和认证;标准库用Handler装饰器模式,gin支持全局/分组/单路由注册,需注意顺序(日志最外、panic恢复顶层)、请求ID追踪及敏感信息脱敏。

如何使用Golang中间件处理请求_统一日志和认证

在 Go Web 开发中,中间件是处理横切关注点(如日志、认证、CORS、超时等)最自然的方式。使用标准 net/http 或主流框架(如 Gin、echo、Fiber)都能轻松实现统一日志和认证逻辑,关键在于把共用逻辑“包一层”——即在真正处理业务前/后插入自定义逻辑。

用函数链式包装实现基础中间件

Go 的 http.Handlerhttp.HandlerFunc 天然支持装饰器模式。一个中间件本质上就是一个接收 http.Handler 并返回新 http.Handler 的函数:

func LoggingMiddleware(next http.Handler) http.Handler {     return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {         start := time.Now()         log.Printf("→ %s %s", r.Method, r.URL.Path)         next.ServeHTTP(w, r)         log.Printf("← %s %s %v", r.Method, r.URL.Path, time.Since(start))     }) }  func AuthMiddleware(next http.Handler) http.Handler {     return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {         auth := r.Header.Get("Authorization")         if auth == "" || !strings.HasPrefix(auth, "Bearer ") {             http.Error(w, "Unauthorized", http.StatusUnauthorized)             return         }         Token := strings.TrimPrefix(auth, "Bearer ")         if !isValidToken(token) { // 你自己的校验逻辑             http.Error(w, "Invalid token", http.StatusUnauthorized)             return         }         next.ServeHTTP(w, r)     }) }

然后按需组合:

handler := http.HandlerFunc(yourHandler) handler = LoggingMiddleware(handler) handler = AuthMiddleware(handler) http.ListenAndServe(":8080", handler)

在 Gin 中更简洁地注册中间件

Gin 把中间件抽象为 gin.HandlerFunc,支持全局、分组、单路由三种挂载方式:

立即学习go语言免费学习笔记(深入)”;

  • 全局中间件(所有路由生效):r.Use(Logging(), Auth())
  • 分组中间件(如只对 API 路由加认证):api := r.Group("/api").Use(Auth())
  • 单路由中间件(特殊接口跳过):r.GET("/health", HealthCheck)(不调用 Use

示例日志中间件(带请求 ID 和结构化输出):

func Logging() gin.HandlerFunc {     return func(c *gin.Context) {         id := uuid.New().String()         c.Header("X-Request-ID", id)         start := time.Now()          c.Next() // 执行后续中间件和 handler          latency := time.Since(start)         status := c.Writer.Status()         method := c.Request.Method         path := c.Request.URL.Path          log.Printf("[GIN] %s | %d | %v | %s %s | %s",             id, status, latency, method, path, c.ClientIP())     } }

认证中间件的实用增强点

真实项目中,认证中间件不应只做“有无 token”,还需考虑:

  • 区分公开/私有接口:用路由分组或自定义属性标记(如 c.Get("skipAuth")),避免白名单硬编码
  • 解析并注入用户信息:校验通过后,把 userIDroles 等写入 c.Set("user", user),下游 handler 可直接取用
  • 支持多种认证方式:如同时接受 Bearer Token、API Key(X-API-Key)、或 cookie(用于管理后台)
  • 错误响应标准化:统一返回 jsON 错误格式(如 {"error": "invalid_token"}),而非裸 http.Error

统一日志建议:关联请求生命周期

单纯打印时间不够,要让一次请求的所有日志可追踪:

  • context.WithValue 或 Gin 的 c.Set 传递 requestID
  • 日志库推荐 log/slog(Go 1.21+)或 zerolog,支持字段追加(如 .Str("req_id", id).Int("status", status)
  • 记录关键上下文:客户端 IP(注意反向代理场景用 X-forwarded-For)、User-Agent、响应大小、是否命中缓存
  • 敏感字段(如密码、token)务必脱敏,日志中显示为 [redACTED]

不复杂但容易忽略的是中间件顺序——日志通常放最外层,认证紧随其后;如果先认证再日志,失败请求可能没日志。另外,panic 恢复中间件应放在最顶层,防止崩溃中断整个链路。

text=ZqhQzanResources