middleware

package
v0.0.0-...-fb81f76 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 23, 2026 License: MIT Imports: 16 Imported by: 0

README

Middleware - Yogan 中间件组件

高质量、可配置的 Gin 中间件集合。

特性

  • TraceID - 请求追踪
  • RequestLog - 结构化请求日志
  • Recovery - Panic 恢复
  • CORS - 跨域支持
  • RateLimiter - 限流控制 ✨

RateLimiter - 限流中间件

特性
  • 支持多种限流算法(Token Bucket、Sliding Window、Concurrency、Adaptive)
  • 支持多种限流维度(路径、IP、用户、API Key)
  • 支持路径跳过和自定义跳过条件
  • 限流器未启用时自动放行
  • 限流器错误时降级放行(高可用)
  • 完全可配置(错误处理、限流响应、键函数)
基本使用
import (
    "github.com/KOMKZ/go-yogan/limiter"
    "github.com/KOMKZ/go-yogan/middleware"
    "github.com/gin-gonic/gin"
)

// 1. 创建限流器
cfg := limiter.Config{
    Enabled:   true,
    StoreType: "memory",
    Resources: map[string]limiter.ResourceConfig{
        "GET:/api/users": {
            Algorithm: "token_bucket",
            Rate:      100,
            Capacity:  200,
        },
    },
}

manager, _ := limiter.NewManagerWithLogger(cfg, log, nil)

// 2. 应用中间件
router := gin.Default()
router.Use(middleware.RateLimiter(manager))
自定义配置
// 配置限流中间件
cfg := middleware.DefaultRateLimiterConfig(manager)

// 按IP限流
cfg.KeyFunc = middleware.RateLimiterKeyByIP

// 跳过特定路径
cfg.SkipPaths = []string{"/health", "/metrics"}

// 自定义限流响应
cfg.RateLimitHandler = func(c *gin.Context) {
    c.JSON(429, gin.H{
        "error": "Too many requests",
        "retry_after": 60,
    })
    c.Abort()
}

// 自定义跳过条件
cfg.SkipFunc = func(c *gin.Context) bool {
    // 管理员不限流
    role, _ := c.Get("role")
    return role == "admin"
}

router.Use(middleware.RateLimiterWithConfig(cfg))
内置键函数
// 1. 默认:按路径限流
// 资源键:GET:/api/users
cfg.KeyFunc = nil  // 或不设置

// 2. 按IP限流
// 资源键:ip:192.168.1.1
cfg.KeyFunc = middleware.RateLimiterKeyByIP

// 3. 按用户限流
// 资源键:user:12345 或 user:anonymous
cfg.KeyFunc = middleware.RateLimiterKeyByUser("user_id")

// 4. 按路径+IP限流
// 资源键:GET:/api/users:192.168.1.1
cfg.KeyFunc = middleware.RateLimiterKeyByPathAndIP

// 5. 按API Key限流
// 资源键:apikey:xxx-xxx 或 apikey:anonymous
cfg.KeyFunc = middleware.RateLimiterKeyByAPIKey("X-API-Key")

// 6. 自定义键函数
cfg.KeyFunc = func(c *gin.Context) string {
    // 按租户ID限流
    tenantID := c.GetHeader("X-Tenant-ID")
    return fmt.Sprintf("tenant:%s:%s", tenantID, c.Request.URL.Path)
}
路由级限流
// 全局限流(所有路由)
router.Use(middleware.RateLimiter(manager))

// 路由组限流
api := router.Group("/api")
api.Use(middleware.RateLimiter(manager))
{
    api.GET("/users", getUsersHandler)
    api.POST("/users", createUserHandler)
}

// 单个路由限流
router.GET("/download",
    middleware.RateLimiter(manager),
    downloadHandler,
)
配置示例
按路径限流(默认)
limiter:
  enabled: true
  store_type: memory
  resources:
    "POST:/api/users":
      algorithm: token_bucket
      rate: 10        # 10 req/s
      capacity: 20
    "GET:/api/users":
      algorithm: sliding_window
      limit: 1000
      window_size: 1m
按IP限流
cfg.KeyFunc = middleware.RateLimiterKeyByIP
cfg.Resources = map[string]limiter.ResourceConfig{
    "ip:*": {  // 所有IP共用配置
        Algorithm: "token_bucket",
        Rate:      100,
        Capacity:  200,
    },
}
按用户限流
// 先设置用户上下文
router.Use(authMiddleware)  // 设置 c.Set("user_id", "xxx")

// 配置限流
cfg.KeyFunc = middleware.RateLimiterKeyByUser("user_id")
cfg.Resources = map[string]limiter.ResourceConfig{
    "user:*": {
        Algorithm: "token_bucket",
        Rate:      50,
        Capacity:  100,
    },
}
高级功能
1. 分布式限流(Redis)
// 使用Redis存储实现分布式限流
cfg := limiter.Config{
    Enabled:   true,
    StoreType: "redis",
    RedisConfig: limiter.RedisStoreConfig{
        Instance: "main",  // 使用的Redis实例名
    },
}
2. 自适应限流
// 根据系统负载动态调整限流
cfg.Resources = map[string]limiter.ResourceConfig{
    "POST:/api/heavy": {
        Algorithm: "adaptive",
        MinLimit:  10,
        MaxLimit:  100,
        TargetCPU: 0.7,  // 目标CPU 70%
    },
}
3. 并发限流
// 控制并发请求数
cfg.Resources = map[string]limiter.ResourceConfig{
    "GET:/api/export": {
        Algorithm:      "concurrency",
        MaxConcurrency: 10,  // 最多10个并发
    },
}
测试
cd src/yogan/middleware
go test -v -run='TestRateLimiter'
监控

限流中间件会发送事件到事件总线,可以订阅这些事件进行监控:

eventBus := manager.GetEventBus()
eventBus.Subscribe(func(e limiter.Event) {
    if e.Type() == limiter.EventRejected {
        log.Warn("请求被限流", 
            zap.String("resource", e.Resource()),
        )
    }
})

其他中间件

TraceID
router.Use(middleware.TraceID(middleware.DefaultTraceConfig()))
RequestLog
cfg := middleware.DefaultRequestLogConfig()
cfg.SkipPaths = []string{"/health"}
router.Use(middleware.RequestLogWithConfig(cfg))
Recovery
router.Use(middleware.Recovery())
CORS
router.Use(middleware.CORS())

License

MIT

Documentation

Index

Constants

View Source
const (
	// TraceIDKeyDefault TraceID key default value in the Context
	TraceIDKeyDefault = "trace_id"

	// The default value for the TraceID key in the TraceIDHeaderDefault HTTP header
	TraceIDHeaderDefault = "X-Trace-ID"
)

Variables

View Source
var DefaultJWTConfig = JWTConfig{
	Skipper:       nil,
	TokenLookup:   "header:Authorization",
	TokenHeadName: "Bearer",
	ErrorHandler:  defaultJWTErrorHandler,
}

Default JWT Configuration

Functions

func CORS

func CORS() gin.HandlerFunc

Create CORS middleware (using default configuration)

Function: - Handle Cross-Origin Resource Sharing (CORS) - Automatically respond to OPTIONS preflight requests - Set CORS related response headers

Usage:

engine.Use(middleware.CORS())

func CORSWithConfig

func CORSWithConfig(cfg CORSConfig) gin.HandlerFunc

CORSWithConfig creates CORS middleware (custom configuration)

func GetClaims

func GetClaims(c *gin.Context) (*jwt.Claims, bool)

GetClaims retrieves JWT Claims from Context

func GetTraceID

func GetTraceID(c *gin.Context) string

GetTraceID retrieves the TraceID from gin.Context (convenience method) Use default key

func GetTraceIDWithKey

func GetTraceIDWithKey(c *gin.Context, key string) string

GetTraceIDWithKey retrieves the TraceID from gin.Context (specified by Key)

func GetUserID

func GetUserID(c *gin.Context) (int64, bool)

Get user ID from context

func GetUsername

func GetUsername(c *gin.Context) (string, bool)

Get username from context

func HasRole

func HasRole(c *gin.Context, role string) bool

Check if the user has the specified role

func JWT

func JWT(tokenManager jwt.TokenManager) gin.HandlerFunc

Create JWT middleware (using default configuration)

func JWTWithConfig

func JWTWithConfig(tokenManager jwt.TokenManager, config JWTConfig) gin.HandlerFunc

Create JWT middleware with custom configuration

func RateLimiter

func RateLimiter(manager *limiter.Manager) gin.HandlerFunc

Create rate limiting middleware

Function: 1. Rate limiting for requests Supports multiple rate limiting algorithms (Token Bucket, Sliding Window, Concurrency, Adaptive) Supports rate limiting by dimensions such as path, IP, user etc. English: Automatically allow when rate limiter is not enabled English: Downgrade and proceed in case of rate limiter error

Usage:

// Basic usage

engine.Use(middleware.RateLimiter(limiterManager))

// Custom configuration

cfg := middleware.DefaultRateLimiterConfig(limiterManager)
cfg.KeyFunc = middleware.RateLimiterKeyByIP
cfg.SkipPaths = []string{"/health", "/metrics"}
engine.Use(middleware.RateLimiterWithConfig(cfg))

func RateLimiterKeyByAPIKey

func RateLimiterKeyByAPIKey(headerName string) func(*gin.Context) string

RateLimiterKeyByAPIKey generates resource keys based on API key Used for rate limiting by API key (requires obtaining from Header or Query)

Usage:

cfg.KeyFunc = middleware.RateLimiterKeyByAPIKey("X-API-Key")

func RateLimiterKeyByIP

func RateLimiterKeyByIP(c *gin.Context) string

RateLimiterKeyByIP generates resource keys based on client IP Used for IP rate limiting

func RateLimiterKeyByPathAndIP

func RateLimiterKeyByPathAndIP(c *gin.Context) string

RateLimiterKeyByPathAndIP generates a resource key based on path and IP For rate limiting by path+IP combination

func RateLimiterKeyByUser

func RateLimiterKeyByUser(userIDKey string) func(*gin.Context) string

RateLimiterKeyByUser generates resource keys based on user ID For rate limiting by user (requires obtaining user information from context)

Usage:

cfg.KeyFunc = middleware.RateLimiterKeyByUser("user_id")

func RateLimiterWithConfig

func RateLimiterWithConfig(cfg RateLimiterConfig) gin.HandlerFunc

Creates a rate limiter middleware with custom configuration

func Recovery

func Recovery() gin.HandlerFunc

Recovery from Gin panic (structured logging) Replace gin.Recovery() with a custom Logger component to log panic logs Function: - Catch panics in the handler to prevent program crashes - Log complete stack information - Return a unified 500 error response to the client - Do not expose sensitive stack information to clients

func RegisterHealthRoutes

func RegisterHealthRoutes(router gin.IRouter, aggregator *health.Aggregator)

RegisterHealthRoutes Register health check routes Convenient method, automatically registers all health check endpoints

func RequestLog

func RequestLog() gin.HandlerFunc

RequestLog Gin HTTP request logging middleware (structured logs) Replace gin.Logger() with a custom Logger component to log request logs

Function: - Structured log fields (status code, duration, client IP, etc.) - Automatically classify by status code (500+ Error, 400+ Warning, 200+ Information) - Record request error information - Support for automatic association of TraceID (using Context API) - Support skipping specified paths

Usage:

engine.Use(middleware.RequestLog())

// or custom configuration

cfg := middleware.DefaultRequestLogConfig()
cfg.SkipPaths = []string{"/health", "/metrics"}
engine.Use(middleware.RequestLogWithConfig(cfg))

func RequestLogWithConfig

func RequestLogWithConfig(cfg RequestLogConfig) gin.HandlerFunc

Create HTTP request log middleware with custom configuration

func TraceID

func TraceID(cfg TraceConfig) gin.HandlerFunc

Create TraceID middleware

Function: 1. Extract or generate TraceID from Header Inject into gin.Context and context.Context Optional: Write TraceID to Response Header 4. 🎯 Intelligent switch: If OpenTelemetry is enabled, prioritize using the OTel Trace ID

Usage:

engine.Use(middleware.TraceID(middleware.DefaultTraceConfig()))

Types

type CORSConfig

type CORSConfig struct {
	// AllowOrigins list of allowed sources (default ["*"])
	// Example: ["https://example.com", "https://app.example.com"]
	AllowOrigins []string

	// AllowMethods list of allowed HTTP methods (default ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"])
	AllowMethods []string

	// AllowHeaders list of allowed request headers (default ["Origin", "Content-Type", "Accept", "Authorization"])
	AllowHeaders []string

	// ExposeHeaders list of response headers exposed to the client (default [])
	ExposeHeaders []string

	// AllowCredentials whether to allow sending credentials (such as Cookies, HTTP authentication, etc.) (default false)
	// Note: When set to true, AllowOrigins cannot use "*"
	AllowCredentials bool

	// MaxAge preflight request cache time (seconds) (default 43200, i.e., 12 hours)
	MaxAge int
}

CORSConfig CORS middleware configuration

func DefaultCORSConfig

func DefaultCORSConfig() CORSConfig

DefaultCORSConfig default CORS configuration

type HTTPMetrics

type HTTPMetrics struct {
	// contains filtered or unexported fields
}

HTTPMetrics HTTP layer metric collector Implements component.MetricsProvider interface

func NewHTTPMetrics

func NewHTTPMetrics(cfg HTTPMetricsConfig) *HTTPMetrics

Create new HTTP metrics collector

func (*HTTPMetrics) Handler

func (m *HTTPMetrics) Handler() gin.HandlerFunc

Handler returns a Gin middleware for collecting HTTP metrics. Metrics must be registered via RegisterMetrics before calling this.

func (*HTTPMetrics) IsMetricsEnabled

func (m *HTTPMetrics) IsMetricsEnabled() bool

IsMetricsEnabled returns whether metrics collection is enabled

func (*HTTPMetrics) IsRegistered

func (m *HTTPMetrics) IsRegistered() bool

IsRegistered returns whether metrics have been registered

func (*HTTPMetrics) MetricsName

func (m *HTTPMetrics) MetricsName() string

MetricsName returns the metrics group name

func (*HTTPMetrics) RegisterMetrics

func (m *HTTPMetrics) RegisterMetrics(meter metric.Meter) error

RegisterMetrics registers all HTTP metrics with the provided Meter

type HTTPMetricsConfig

type HTTPMetricsConfig struct {
	Enabled            bool
	RecordRequestSize  bool
	RecordResponseSize bool
}

HTTP Metrics Config HTTP metric configuration

type HealthCheckHandler

type HealthCheckHandler struct {
	// contains filtered or unexported fields
}

HealthCheckHandler health check HTTP handler Provide a unified health check endpoint

func NewHealthCheckHandler

func NewHealthCheckHandler(aggregator *health.Aggregator) *HealthCheckHandler

Create new health check handler

func (*HealthCheckHandler) Handle

func (h *HealthCheckHandler) Handle() gin.HandlerFunc

Handle health check request GET /health - Full health check GET /health/liveness - Liveness probe (K8s liveness probe) GET /health/readiness - Readiness probe (K8s readiness probe)

func (*HealthCheckHandler) HandleLiveness

func (h *HealthCheckHandler) HandleLiveness() gin.HandlerFunc

HandleLiveness K8s Liveness Probe A simple check to see if the application is alive (does not check dependencies)

func (*HealthCheckHandler) HandleReadiness

func (h *HealthCheckHandler) HandleReadiness() gin.HandlerFunc

HandleReadiness K8s Readiness Probe Check if the application is ready (including all dependencies)

type JWTConfig

type JWTConfig struct {
	// Skip function for middleware
	Skipper func(*gin.Context) bool

	// Token lookup position (format: header:Authorization)
	TokenLookup string

	// TokenHeadName Token prefix (such as "Bearer")
	TokenHeadName string

	// Error handler function
	ErrorHandler func(*gin.Context, error)
}

JWTConfig JWT middleware configuration

type RateLimiterConfig

type RateLimiterConfig struct {
	// Manager Rate Limiter Manager (required)
	Manager *limiter.Manager

	// KeyFunc custom resource key generation function (default: method:path)
	KeyFunc func(*gin.Context) string

	// ErrorHandler custom error handling function (default: log errors but proceed)
	ErrorHandler func(*gin.Context, error)

	// RateLimitHandler custom rate limiting response function (default: return 429)
	RateLimitHandler func(*gin.Context)

	// SkipFunc optional function to skip rate limiting conditions
	SkipFunc func(*gin.Context) bool

	// SkipPaths list of paths to bypass rate limiting (optional)
	SkipPaths []string
}

RateLimiterConfig rate limiting middleware configuration

func DefaultRateLimiterConfig

func DefaultRateLimiterConfig(manager *limiter.Manager) RateLimiterConfig

DefaultRateLimiterConfig default rate limiting configuration

type RequestLogConfig

type RequestLogConfig struct {
	// SkipPaths list of paths to skip recording
	SkipPaths []string

	// EnableBody Whether to log request body (considering performance, default is false)
	EnableBody bool

	// MaxBodySize maximum request body recording size (bytes)
	MaxBodySize int
}

HTTP request log configuration

func DefaultRequestLogConfig

func DefaultRequestLogConfig() RequestLogConfig

Default request log configuration

type TraceConfig

type TraceConfig struct {
	// TraceIDKey stored in Context (default "trace_id")
	TraceIDKey string

	// TraceIDHeader is the key in the HTTP Header (default "X-Trace-ID")
	TraceIDHeader string

	// EnableResponseHeader whether to write TraceID into Response Header (default true)
	EnableResponseHeader bool

	// Generator custom TraceID generator (default uses UUID)
	Generator func() string
}

TraceConfig Trace middleware configuration

func DefaultTraceConfig

func DefaultTraceConfig() TraceConfig

Default configuration for DefaultTraceConfig

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL