golang http框架 middleware作用和案例

http中间件的作用

在Go语言的HTTP框架中,中间件(Middleware)是一种在请求到达处理器之前或之后执行特定逻辑的机制。中间件通常用于处理横切关注点,例如日志记录、身份验证、请求处理、错误处理等。

中间件的主要作用包括:

  • 请求预处理:如身份验证、请求日志记录、请求数据校验
  • 响应后处理:如响应日志记录、错误处理、数据格式化
  • 处理链控制:可以决定是否继续处理请求或直接返回响应

常见的中间件实现方式

大多数Go HTTP框架通过HandlerFunc的链式调用来实现中间件模式。基本模式是包装http.Handler或http.HandlerFunc,在调用实际处理函数前后执行额外逻辑。

func middleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // 前置处理逻辑
        log.Println("Before handler")
        
        // 调用下一个处理程序
        next.ServeHTTP(w, r)
        
        // 后置处理逻辑
        log.Println("After handler")
    })
}

主流框架的中间件实现案例

Gin框架中间件

Gin是流行的Go Web框架,其中间件使用非常简单:

package main

import "github.com/gin-gonic/gin"

func LoggerMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 请求前处理
        start := time.Now()
        
        // 处理请求
        c.Next()
        
        // 请求后处理
        latency := time.Since(start)
        log.Printf("Request took %v", latency)
    }
}

func main() {
    r := gin.Default()
    
    // 全局中间件
    r.Use(LoggerMiddleware())
    
    // 路由特定中间件
    r.GET("/ping", LoggerMiddleware(), func(c *gin.Context) {
        c.String(200, "pong")
    })
    
    r.Run()
}
Echo框架中间件

Echo框架也提供了简洁的中间件机制:

package main

import (
    "github.com/labstack/echo/v4"
    "github.com/labstack/echo/v4/middleware"
)

func CustomMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
    return func(c echo.Context) error {
        // 请求前处理
        c.Response().Header().Set("X-Custom-Header", "Middleware")
        
        // 调用下一个处理程序
        return next(c)
    }
}

func main() {
    e := echo.New()
    
    // 内置中间件
    e.Use(middleware.Logger())
    
    // 自定义中间件
    e.Use(CustomMiddleware)
    
    e.GET("/", func(c echo.Context) error {
        return c.String(200, "Hello, Middleware!")
    })
    
    e.Start(":8080")
}
标准库net/http中间件

即使不使用框架,标准库也能实现中间件模式:

package main

import (
    "log"
    "net/http"
    "time"
)

func loggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()
        
        log.Printf("Started %s %s", r.Method, r.URL.Path)
        
        next.ServeHTTP(w, r)
        
        log.Printf("Completed %s in %v", r.URL.Path, time.Since(start))
    })
}

func authMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        token := r.Header.Get("Authorization")
        if token != "secret" {
            http.Error(w, "Unauthorized", http.StatusUnauthorized)
            return
        }
        next.ServeHTTP(w, r)
    })
}

func mainHandler(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Authenticated and Logged"))
}

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/", mainHandler)
    
    // 应用中间件链
    handler := loggingMiddleware(authMiddleware(mux))
    
    http.ListenAndServe(":8080", handler)
}

中间件的常见应用场景

认证中间件

验证请求是否具有有效的认证凭据:

func AuthMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        token := r.Header.Get("Authorization")
        if !isValidToken(token) {
            http.Error(w, "Unauthorized", http.StatusUnauthorized)
            return
        }
        next.ServeHTTP(w, r)
    })
}
日志记录中间件

记录请求和响应信息:

func LoggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        log.Printf("Incoming request: %s %s", r.Method, r.URL.Path)
        
        rw := &responseWriter{ResponseWriter: w}
        next.ServeHTTP(rw, r)
        
        log.Printf("Response: %d %s", rw.status, http.StatusText(rw.status))
    })
}

type responseWriter struct {
    http.ResponseWriter
    status int
}

func (rw *responseWriter) WriteHeader(code int) {
    rw.status = code
    rw.ResponseWriter.WriteHeader(code)
}
跨域中间件

处理CORS请求:

func CORSMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Access-Control-Allow-Origin", "*")
        w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
        w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
        
        if r.Method == "OPTIONS" {
            w.WriteHeader(http.StatusOK)
            return
        }
        
        next.ServeHTTP(w, r)
    })
}
限流中间件

限制请求频率:

func RateLimitMiddleware(next http.Handler) http.Handler {
    limiter := rate.NewLimiter(100, 30) // 每秒100个请求,突发30个
    
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        if !limiter.Allow() {
            http.Error(w, "Too Many Requests", http.StatusTooManyRequests)
            return
        }
        next.ServeHTTP(w, r)
    })
}

中间件链的最佳实践

在设计中间件时,应遵循以下原则:

  • 单一职责:每个中间件应只关注一个功能
  • 明确顺序:中间件的执行顺序很重要,如认证应在授权之前
  • 性能考虑:避免在中间件中执行耗时操作
  • 错误处理:中间件应正确处理错误并适当终止请求处理链
  • 可测试性:中间件应设计为可独立测试的单元

通过合理使用中间件,可以构建出结构清晰、功能强大且易于维护的Go HTTP应用。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云原生运维

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值