高级中间件模式
1. 中间件链的深入理解
Go的中间件本质上是函数链式调用:
func MiddlewareChain(handlers ...gin.HandlerFunc) gin.HandlerFunc {
return func(c *gin.Context) {
// 创建处理函数链
chain := func(idx int) gin.HandlerFunc {
if idx == len(handlers) {
return nil
}
return func(c *gin.Context) {
handlers[idx](c)
if c.IsAborted() {
return
}
chain(idx+1)(c)
}
}
chain(0)(c)
}
}
// 使用示例
r.GET("/", MiddlewareChain(
LoggerMiddleware,
AuthMiddleware,
RateLimitMiddleware,
func(c *gin.Context) {
c.String(200, "Hello")
},
))
2. 上下文传递模式
中间件间可以通过context传递数据:
// 定义上下文键类型
type contextKey string
const (
requestIDKey contextKey = "requestID"
)
// 设置请求ID的中间件
func RequestIDMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// 生成唯一请求ID
id := uuid.New().String()
// 存储到context中
c.Set(string(requestIDKey), id)
// 设置响应头
c.Header("X-Request-ID", id)
c.Next()
}
}
// 获取请求ID的函数
func GetRequestID(c *gin.Context) string {
if val, exists := c.Get(string(requestIDKey)); exists {
return val.(string)
}
return ""
}
// 日志中间件使用请求ID
func LoggingMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
c.Next()
log.Printf("[%s] %s %s %s %v",
GetRequestID(c),
c.Request.Method,
c.Request.URL.Path,
c.ClientIP(),
time.Since(start),
)
}
}
3. 可配置中间件
通过闭包创建可配置的中间件:
// 可配置的CORS中间件
func CORSMiddleware(allowedOrigins []string) gin.HandlerFunc {
return func(c *gin.Context) {
origin := c.Request.Header.Get("Origin")
// 检查来源是否允许
for _, o := range allowedOrigins {
if o == origin || o == "*" {
c.Header("Access-Control-Allow-Origin", origin)
c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization")
c.Header("Access-Control-Allow-Credentials", "true")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
break
}
}
c.Next()
}
}
// 使用示例
r.Use(CORSMiddleware([]string{
"https://example.com",
"https://api.example.com",
}))
4. 性能监控中间件
// 性能监控中间件
func MetricsMiddleware(metricsClient *prometheus.Client) gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
path := c.Request.URL.Path
// 记录请求开始
metricsClient.Inc("http_requests_total", 1,
prometheus.Labels{"path": path, "method": c.Request.Method})
c.Next()
// 记录请求耗时和状态码
duration := time.Since(start).Seconds()
metricsClient.Observe("http_request_duration_seconds", duration,
prometheus.Labels{"path": path})
metricsClient.Inc("http_responses_total", 1,
prometheus.Labels{"path": path, "status": strconv.Itoa(c.Writer.Status())})
}
}
// 配合Prometheus使用
r.GET("/metrics", gin.WrapH(promhttp.Handler()))
5. 分布式追踪集成
// Jaeger分布式追踪中间件
func TracingMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// 从请求头中提取追踪上下文
spanCtx, _ := opentracing.GlobalTracer().Extract(
opentracing.HTTPHeaders,
opentracing.HTTPHeadersCarrier(c.Request.Header),
)
// 创建新的span
span := opentracing.StartSpan(
c.Request.URL.Path,
opentracing.ChildOf(spanCtx),
opentracing.Tag{Key: "http.method", Value: c.Request.Method},
)
defer span.Finish()
// 将span存入context
ctx := opentracing.ContextWithSpan(c.Request.Context(), span)
c.Request = c.Request.WithContext(ctx)
// 设置响应头
c.Header("X-Trace-ID", span.Context().(jaeger.SpanContext).TraceID().String())
c.Next()
// 记录响应状态码
span.SetTag("http.status_code", c.Writer.Status())
}
}
// 初始化追踪器
func initTracing(serviceName string) (opentracing.Tracer, io.Closer) {
cfg := jaegerConfig.Configuration{
ServiceName: serviceName,
Sampler: &jaegerConfig.SamplerConfig{
Type: "const",
Param: 1,
},
Reporter: &jaegerConfig.ReporterConfig{
LogSpans: true,
},
}
return cfg.NewTracer()
}
提示:高级中间件模式可以极大提升应用的可观测性和可维护性,但也要注意性能开销。建议根据实际需求选择适当的中间件组合。
