Files
go-common/docs/middleware.md

26 KiB
Raw Permalink Blame History

中间件工具文档

概述

中间件工具提供了常用的HTTP中间件功能包括CORS处理、时区管理、请求日志、Panic恢复和限流等。

功能特性

  • CORS中间件:支持跨域资源共享配置
  • 时区中间件:从请求头读取时区信息,支持默认时区设置
  • 日志中间件自动记录每个HTTP请求的详细信息
  • Recovery中间件捕获panic并恢复防止服务崩溃
  • 限流中间件:基于令牌桶算法的请求限流
  • 中间件链:提供便捷的中间件链式调用

CORS中间件

功能说明

CORS中间件用于处理跨域资源共享支持

  • 配置允许的源(支持通配符)
  • 配置允许的HTTP方法
  • 配置允许的请求头
  • 配置暴露的响应头
  • 支持凭证传递
  • 预检请求缓存时间设置

使用方法

基本使用(默认配置)

import (
    "net/http"
    "git.toowon.com/jimmy/go-common/middleware"
)

func main() {
    handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // 处理请求
    })

    // 使用默认CORS配置
    corsHandler := middleware.CORS()(handler)

    http.Handle("/api", corsHandler)
    http.ListenAndServe(":8080", nil)
}

自定义配置

import (
    "net/http"
    "git.toowon.com/jimmy/go-common/middleware"
)

func main() {
    // 自定义CORS配置
    corsConfig := &middleware.CORSConfig{
        AllowedOrigins: []string{
            "https://example.com",
            "https://app.example.com",
            "*.example.com", // 支持通配符
        },
        AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
        AllowedHeaders: []string{
            "Content-Type",
            "Authorization",
            "X-Requested-With",
            "X-Timezone",
        },
        ExposedHeaders: []string{"X-Total-Count"},
        AllowCredentials: true,
        MaxAge: 3600, // 1小时
    }

    handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // 处理请求
    })

    corsHandler := middleware.CORS(corsConfig)(handler)

    http.Handle("/api", corsHandler)
    http.ListenAndServe(":8080", nil)
}

允许所有源(开发环境)

corsConfig := &middleware.CORSConfig{
    AllowedOrigins: []string{"*"},
    AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
    AllowedHeaders: []string{"*"},
}

corsHandler := middleware.CORS(corsConfig)(handler)

CORSConfig 配置说明

字段 类型 说明 默认值
AllowedOrigins []string 允许的源,支持 "" 和 ".example.com" ["*"]
AllowedMethods []string 允许的HTTP方法 ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]
AllowedHeaders []string 允许的请求头 ["Content-Type", "Authorization", "X-Requested-With", "X-Timezone"]
ExposedHeaders []string 暴露给客户端的响应头 []
AllowCredentials bool 是否允许发送凭证 false
MaxAge int 预检请求缓存时间(秒) 86400

注意事项

  1. 如果 AllowCredentialstrueAllowedOrigins 不能使用 "*",必须指定具体的源
  2. 通配符支持:"*.example.com" 会匹配 "https://app.example.com" 等子域名
  3. 预检请求OPTIONS会自动处理无需在业务代码中处理

时区中间件

功能说明

时区中间件用于从请求头读取时区信息并存储到context中方便后续使用。

  • 从请求头 X-Timezone 读取时区
  • 如果未传递时区信息,使用默认时区 AsiaShanghai
  • 时区信息存储到context中可通过Handler的GetTimezone()方法获取
  • 自动验证时区有效性,无效时区会回退到默认时区

使用方法

基本使用(默认时区 AsiaShanghai

import (
    "net/http"
    "git.toowon.com/jimmy/go-common/middleware"
    commonhttp "git.toowon.com/jimmy/go-common/http"
    "git.toowon.com/jimmy/go-common/datetime"
)

func handler(w http.ResponseWriter, r *http.Request) {
    h := commonhttp.NewHandler(w, r)
    
    // 从Handler获取时区
    timezone := h.GetTimezone()
    
    // 使用时区
    now := datetime.Now(timezone)
    datetime.FormatDateTime(now, timezone)
    
    h.Success(map[string]interface{}{
        "timezone": timezone,
        "time": datetime.FormatDateTime(now),
    })
}

func main() {
    handler := middleware.Timezone(http.HandlerFunc(handler))
    http.Handle("/api", handler)
    http.ListenAndServe(":8080", nil)
}

自定义默认时区

import (
    "net/http"
    "git.toowon.com/jimmy/go-common/middleware"
    "git.toowon.com/jimmy/go-common/datetime"
)

func handler(w http.ResponseWriter, r *http.Request) {
    // 处理请求
}

func main() {
    // 使用自定义默认时区
    handler := middleware.TimezoneWithDefault(datetime.UTC)(http.HandlerFunc(handler))
    http.Handle("/api", handler)
    http.ListenAndServe(":8080", nil)
}

在业务代码中使用时区

import (
    "net/http"
    commonhttp "git.toowon.com/jimmy/go-common/http"
    "git.toowon.com/jimmy/go-common/datetime"
)

func GetUserList(w http.ResponseWriter, r *http.Request) {
    h := commonhttp.NewHandler(w, r)
    
    // 从Handler获取时区
    timezone := h.GetTimezone()
    
    // 使用时区进行时间处理
    now := datetime.Now(timezone)
    
    // 查询数据时使用时区
    startTime := datetime.StartOfDay(now, timezone)
    endTime := datetime.EndOfDay(now, timezone)
    
    // 返回数据
    h.Success(map[string]interface{}{
        "timezone": timezone,
        "startTime": datetime.FormatDateTime(startTime),
        "endTime": datetime.FormatDateTime(endTime),
    })
}

请求头格式

客户端需要在请求头中传递时区信息:

X-Timezone: Asia/Shanghai

支持的时区格式IANA时区数据库

  • Asia/Shanghai
  • America/New_York
  • Europe/London
  • UTC
  • 等等

注意事项

  1. 如果请求头中未传递 X-Timezone,默认使用 AsiaShanghai
  2. 如果传递的时区无效,会自动回退到默认时区
  3. 时区信息存储在context中可以在整个请求生命周期中使用
  4. 建议在CORS配置中包含 X-Timezone 请求头

日志中间件

功能说明

日志中间件用于自动记录每个HTTP请求的详细信息帮助监控和调试应用。

记录内容包括:

  • 请求方法、路径、查询参数
  • 响应状态码、响应大小
  • 请求处理时间(毫秒)
  • 客户端IP地址支持X-Forwarded-For
  • User-Agent、Referer等信息

使用方法

基本使用使用默认logger

import (
    "net/http"
    "git.toowon.com/jimmy/go-common/middleware"
)

func main() {
    chain := middleware.NewChain(
        middleware.Logging(nil), // 使用默认配置
        middleware.CORS(),
        middleware.Timezone,
    )

    handler := chain.ThenFunc(apiHandler)
    http.Handle("/api", handler)
    http.ListenAndServe(":8080", nil)
}

使用自定义logger

import (
    "git.toowon.com/jimmy/go-common/middleware"
    "git.toowon.com/jimmy/go-common/logger"
)

func main() {
    // 创建自定义logger异步模式输出到文件
    loggerConfig := &logger.LoggerConfig{
        Level:      "info",
        Output:     "file",
        FilePath:   "./logs/app.log",
        Async:      true,        // 异步模式,不阻塞请求
        BufferSize: 1000,
    }
    myLogger, _ := logger.NewLogger(loggerConfig)

    // 配置日志中间件
    loggingConfig := &middleware.LoggingConfig{
        Logger: myLogger,
        SkipPaths: []string{"/health", "/metrics"}, // 跳过健康检查接口
    }

    chain := middleware.NewChain(
        middleware.Logging(loggingConfig),
        middleware.CORS(),
        middleware.Timezone,
    )

    handler := chain.ThenFunc(apiHandler)
    http.Handle("/api", handler)
    http.ListenAndServe(":8080", nil)
}

LoggingConfig 配置说明

字段 类型 说明 默认值
Logger *logger.Logger 日志记录器 创建默认loggerstdout
SkipPaths []string 跳过记录的路径列表 []
LogRequestBody bool 是否记录请求体(慎用) false
LogResponseBody bool 是否记录响应体(慎用) false

日志输出示例

[INFO] HTTP Request method=GET path=/api/users query= status=200 size=1024 duration=45 ip=192.168.1.100 user_agent=Mozilla/5.0 referer=
[WARN] HTTP Request method=POST path=/api/users query= status=400 size=128 duration=12 ip=192.168.1.100 user_agent=PostmanRuntime/7.29
[ERROR] HTTP Request method=GET path=/api/error query= status=500 size=256 duration=89 ip=192.168.1.100 user_agent=curl/7.64.1 referer=

注意事项

  1. 异步模式推荐生产环境建议使用异步logger避免日志写入阻塞请求
  2. 跳过路径:健康检查、监控接口等高频接口建议跳过日志记录
  3. 日志级别根据状态码自动选择日志级别5xx=ERROR, 4xx=WARN, 2xx-3xx=INFO
  4. 客户端IP自动从X-Forwarded-For、X-Real-IP或RemoteAddr获取真实IP

Recovery中间件

功能说明

Recovery中间件用于捕获HTTP处理过程中的panic防止panic导致整个服务崩溃。

功能包括:

  • 捕获panic并恢复服务
  • 记录panic信息和堆栈跟踪
  • 返回500错误响应
  • 支持自定义错误处理

使用方法

基本使用(使用默认配置)

import (
    "net/http"
    "git.toowon.com/jimmy/go-common/middleware"
)

func main() {
    chain := middleware.NewChain(
        middleware.Recovery(nil), // 使用默认配置
        middleware.Logging(nil),
        middleware.CORS(),
        middleware.Timezone,
    )

    handler := chain.ThenFunc(apiHandler)
    http.Handle("/api", handler)
    http.ListenAndServe(":8080", nil)
}

使用自定义logger

import (
    "git.toowon.com/jimmy/go-common/middleware"
    "git.toowon.com/jimmy/go-common/logger"
)

func main() {
    myLogger, _ := logger.NewLogger(nil)

    recoveryConfig := &middleware.RecoveryConfig{
        Logger:           myLogger,
        EnableStackTrace: true, // 启用堆栈跟踪
    }

    chain := middleware.NewChain(
        middleware.Recovery(recoveryConfig),
        middleware.Logging(nil),
    )

    handler := chain.ThenFunc(apiHandler)
    http.Handle("/api", handler)
    http.ListenAndServe(":8080", nil)
}

自定义错误响应

import (
    "net/http"
    commonhttp "git.toowon.com/jimmy/go-common/http"
    "git.toowon.com/jimmy/go-common/middleware"
)

func main() {
    recoveryConfig := &middleware.RecoveryConfig{
        EnableStackTrace: true,
        CustomHandler: func(w http.ResponseWriter, r *http.Request, err interface{}) {
            // 使用统一的JSON响应格式
            h := commonhttp.NewHandler(w, r)
            h.SystemError("服务器内部错误")
        },
    }

    chain := middleware.NewChain(
        middleware.Recovery(recoveryConfig),
    )

    handler := chain.ThenFunc(apiHandler)
    http.Handle("/api", handler)
    http.ListenAndServe(":8080", nil)
}

RecoveryConfig 配置说明

字段 类型 说明 默认值
Logger *logger.Logger 日志记录器 创建默认logger
EnableStackTrace bool 是否记录堆栈跟踪 true
CustomHandler func(...) 自定义错误处理函数 nil返回500文本

注意事项

  1. 放在最外层Recovery中间件应该放在中间件链的最前面以捕获所有panic
  2. 日志记录建议配置logger确保panic信息被记录下来
  3. 堆栈跟踪:生产环境建议启用,方便排查问题
  4. 自定义响应:可以自定义错误响应格式,统一错误处理

限流中间件

功能说明

限流中间件用于限制请求频率防止API被滥用或遭受攻击。

特性:

  • 基于令牌桶算法
  • 支持按IP、用户ID等维度限流
  • 自动设置限流响应头
  • 内存存储,自动清理过期数据

使用方法

基本使用默认配置100请求/分钟)

import (
    "net/http"
    "git.toowon.com/jimmy/go-common/middleware"
)

func main() {
    chain := middleware.NewChain(
        middleware.Recovery(nil),
        middleware.Logging(nil),
        middleware.RateLimit(nil), // 默认100请求/分钟按IP限流
        middleware.CORS(),
    )

    handler := chain.ThenFunc(apiHandler)
    http.Handle("/api", handler)
    http.ListenAndServe(":8080", nil)
}

自定义限流规则

import (
    "time"
    "git.toowon.com/jimmy/go-common/middleware"
)

func main() {
    // 创建限流器10请求/分钟
    limiter := middleware.NewTokenBucketLimiter(10, time.Minute)

    rateLimitConfig := &middleware.RateLimitConfig{
        Limiter: limiter,
    }

    chain := middleware.NewChain(
        middleware.RateLimit(rateLimitConfig),
    )

    handler := chain.ThenFunc(apiHandler)
    http.Handle("/api", handler)
    http.ListenAndServe(":8080", nil)
}

按用户ID限流

import (
    "net/http"
    "time"
    "git.toowon.com/jimmy/go-common/middleware"
)

func main() {
    limiter := middleware.NewTokenBucketLimiter(100, time.Minute)

    rateLimitConfig := &middleware.RateLimitConfig{
        Limiter: limiter,
        KeyFunc: func(r *http.Request) string {
            // 从请求头或JWT token中获取用户ID
            userID := r.Header.Get("X-User-ID")
            if userID != "" {
                return "user:" + userID
            }
            // 如果没有用户ID使用IP
            return "ip:" + r.RemoteAddr
        },
        OnRateLimitExceeded: func(w http.ResponseWriter, r *http.Request, key string) {
            // 记录限流事件
            println("Rate limit exceeded for:", key)
        },
    }

    chain := middleware.NewChain(
        middleware.RateLimit(rateLimitConfig),
    )

    handler := chain.ThenFunc(apiHandler)
    http.Handle("/api", handler)
    http.ListenAndServe(":8080", nil)
}

便捷函数

// 按IP限流10请求/分钟
chain := middleware.NewChain(
    middleware.RateLimitByIP(10, time.Minute),
)

// 或使用自定义速率
chain := middleware.NewChain(
    middleware.RateLimitWithRate(50, time.Minute),
)

RateLimitConfig 配置说明

字段 类型 说明 默认值
Limiter RateLimiter 限流器实例 100请求/分钟
KeyFunc func(*http.Request) string 生成限流键的函数 使用客户端IP
OnRateLimitExceeded func(...) 限流触发回调 nil

响应头说明

限流中间件会自动设置以下响应头:

响应头 说明
X-RateLimit-Limit 窗口期内允许的请求数
X-RateLimit-Remaining 当前窗口剩余配额
X-RateLimit-Reset 配额重置时间Unix时间戳
Retry-After 限流时,建议重试的等待时间(秒)

响应示例

正常请求:

HTTP/1.1 200 OK
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1640000000

触发限流:

HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1640000000
Retry-After: 45
Too Many Requests

注意事项

  1. 内存存储当前实现使用内存存储适用于单机部署。如需分布式限流建议使用Redis
  2. 键设计合理设计限流键可以按IP、用户、API等维度限流
  3. 清理机制:自动清理过期的限流数据,避免内存泄漏
  4. 算法选择:使用令牌桶算法,支持突发流量

中间件链

功能说明

中间件链提供便捷的中间件组合方式,支持链式调用。

使用方法

import (
    "net/http"
    "git.toowon.com/jimmy/go-common/middleware"
)

func handler(w http.ResponseWriter, r *http.Request) {
    // 处理请求
}

func main() {
    // 创建中间件链
    chain := middleware.NewChain(
        middleware.CORS(),
        middleware.Timezone,
    )

    // 应用到处理器
    handler := chain.ThenFunc(handler)

    http.Handle("/api", handler)
    http.ListenAndServe(":8080", nil)
}

链式追加中间件

chain := middleware.NewChain(middleware.CORS())
chain.Append(middleware.Timezone)

handler := chain.ThenFunc(handler)

完整示例

示例1完整的生产级中间件配置

package main

import (
    "log"
    "net/http"
    "time"
    
    "git.toowon.com/jimmy/go-common/middleware"
    "git.toowon.com/jimmy/go-common/logger"
    commonhttp "git.toowon.com/jimmy/go-common/http"
    "git.toowon.com/jimmy/go-common/datetime"
)

func apiHandler(w http.ResponseWriter, r *http.Request) {
    h := commonhttp.NewHandler(w, r)
    
    // 从Handler获取时区
    timezone := h.GetTimezone()
    now := datetime.Now(timezone)
    
    h.Success(map[string]interface{}{
        "message": "Hello",
        "timezone": timezone,
        "time": datetime.FormatDateTime(now),
    })
}

func main() {
    // 1. 配置logger异步模式输出到文件
    loggerConfig := &logger.LoggerConfig{
        Level:      "info",
        Output:     "both", // 同时输出到stdout和文件
        FilePath:   "./logs/app.log",
        Async:      true,
        BufferSize: 1000,
    }
    myLogger, err := logger.NewLogger(loggerConfig)
    if err != nil {
        log.Fatal(err)
    }
    defer myLogger.Close() // 确保程序退出时关闭logger

    // 2. 配置CORS
    corsConfig := &middleware.CORSConfig{
        AllowedOrigins: []string{"*"},
        AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
        AllowedHeaders: []string{"Content-Type", "Authorization", "X-Timezone"},
    }

    // 3. 配置日志中间件
    loggingConfig := &middleware.LoggingConfig{
        Logger:    myLogger,
        SkipPaths: []string{"/health", "/metrics"},
    }

    // 4. 配置Recovery中间件
    recoveryConfig := &middleware.RecoveryConfig{
        Logger:           myLogger,
        EnableStackTrace: true,
        CustomHandler: func(w http.ResponseWriter, r *http.Request, err interface{}) {
            h := commonhttp.NewHandler(w, r)
            h.SystemError("服务器内部错误")
        },
    }

    // 5. 配置限流中间件100请求/分钟)
    rateLimiter := middleware.NewTokenBucketLimiter(100, time.Minute)
    rateLimitConfig := &middleware.RateLimitConfig{
        Limiter: rateLimiter,
        OnRateLimitExceeded: func(w http.ResponseWriter, r *http.Request, key string) {
            myLogger.Warnf(map[string]interface{}{
                "key": key,
                "path": r.URL.Path,
            }, "Rate limit exceeded")
        },
    }

    // 6. 创建中间件链(顺序很重要!)
    chain := middleware.NewChain(
        middleware.Recovery(recoveryConfig), // 最外层捕获panic
        middleware.Logging(loggingConfig),   // 日志记录
        middleware.RateLimit(rateLimitConfig), // 限流
        middleware.CORS(corsConfig),         // CORS处理
        middleware.Timezone,                 // 时区处理
    )

    // 7. 应用中间件
    http.Handle("/api", chain.ThenFunc(apiHandler))
    http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("OK"))
    })
    
    log.Println("Server started on :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

示例2基础的CORS + 时区中间件

package main

import (
    "log"
    "net/http"
    
    "git.toowon.com/jimmy/go-common/middleware"
    commonhttp "git.toowon.com/jimmy/go-common/http"
    "git.toowon.com/jimmy/go-common/datetime"
)

func apiHandler(w http.ResponseWriter, r *http.Request) {
    h := commonhttp.NewHandler(w, r)
    
    // 从Handler获取时区
    timezone := h.GetTimezone()
    now := datetime.Now(timezone)
    
    h.Success(map[string]interface{}{
        "message": "Hello",
        "timezone": timezone,
        "time": datetime.FormatDateTime(now),
    })
}

func main() {
    // 创建简单的中间件链
    chain := middleware.NewChain(
        middleware.CORS(nil),  // 使用默认CORS配置
        middleware.Timezone,   // 使用默认时区
    )

    http.Handle("/api", chain.ThenFunc(apiHandler))
    
    log.Println("Server started on :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

示例2与路由框架集成

package main

import (
    "net/http"
    
    "git.toowon.com/jimmy/go-common/middleware"
    commonhttp "git.toowon.com/jimmy/go-common/http"
)

func main() {
    mux := http.NewServeMux()
    
    // 创建中间件链
    chain := middleware.NewChain(
        middleware.CORS(),
        middleware.Timezone,
    )

    // 应用中间件到所有路由
    mux.Handle("/api/users", chain.ThenFunc(getUsers))
    mux.Handle("/api/posts", chain.ThenFunc(getPosts))

    http.ListenAndServe(":8080", mux)
}

func getUsers(w http.ResponseWriter, r *http.Request) {
    h := commonhttp.NewHandler(w, r)
    timezone := h.GetTimezone()
    // 处理逻辑
    h.Success(nil)
}

func getPosts(w http.ResponseWriter, r *http.Request) {
    h := commonhttp.NewHandler(w, r)
    timezone := h.GetTimezone()
    // 处理逻辑
    h.Success(nil)
}

API 参考

CORS中间件

CORS(config ...*CORSConfig) func(http.Handler) http.Handler

创建CORS中间件。

参数:

  • config: 可选的CORS配置不指定则使用默认配置

返回: 中间件函数

DefaultCORSConfig() *CORSConfig

返回默认的CORS配置。

时区中间件

Timezone(next http.Handler) http.Handler

时区处理中间件(默认时区为 AsiaShanghai

TimezoneWithDefault(defaultTimezone string) func(http.Handler) http.Handler

时区处理中间件(可自定义默认时区)。

参数:

  • defaultTimezone: 默认时区字符串

返回: 中间件函数

GetTimezoneFromContext(ctx context.Context) string

从context中获取时区。

日志中间件

Logging(config *LoggingConfig) func(http.Handler) http.Handler

创建日志中间件。

参数:

  • config: 日志配置nil则使用默认配置

返回: 中间件函数

Recovery中间件

Recovery(config *RecoveryConfig) func(http.Handler) http.Handler

创建Recovery中间件。

参数:

  • config: Recovery配置nil则使用默认配置

返回: 中间件函数

RecoveryWithLogger(log *logger.Logger) func(http.Handler) http.Handler

使用指定logger的Recovery中间件便捷函数

RecoveryWithCustomHandler(customHandler func(...)) func(http.Handler) http.Handler

使用自定义错误处理的Recovery中间件便捷函数

限流中间件

RateLimit(config *RateLimitConfig) func(http.Handler) http.Handler

创建限流中间件。

参数:

  • config: 限流配置nil则使用默认配置100请求/分钟)

返回: 中间件函数

NewTokenBucketLimiter(rate int, windowSize time.Duration) RateLimiter

创建令牌桶限流器。

参数:

  • rate: 每个窗口期允许的请求数
  • windowSize: 窗口大小

返回: 限流器实例

RateLimitWithRate(rate int, windowSize time.Duration) func(http.Handler) http.Handler

使用指定速率创建限流中间件(便捷函数)。

RateLimitByIP(rate int, windowSize time.Duration) func(http.Handler) http.Handler

按IP限流便捷函数

中间件链

NewChain(middlewares ...func(http.Handler) http.Handler) *Chain

创建新的中间件链。

(c *Chain) Then(handler http.Handler) http.Handler

将中间件链应用到处理器。

(c *Chain) ThenFunc(handler http.HandlerFunc) http.Handler

将中间件链应用到处理器函数。

(c *Chain) Append(middlewares ...func(http.Handler) http.Handler) *Chain

追加中间件到链中。

注意事项

1. CORS配置

  • 生产环境建议明确指定允许的源,避免使用 "*"
  • 如果使用凭证cookies必须明确指定源不能使用 "*"
  • CORS中间件应该在Recovery和Logging之后以便正确处理预检请求

2. 时区处理

  • 时区信息存储在context中确保中间件在处理器之前执行
  • 时区验证失败时会自动回退到默认时区,不会返回错误
  • 建议在CORS配置中包含 X-Timezone 请求头

3. 日志记录

  • 生产环境推荐异步模式:避免日志写入阻塞请求,提升性能
  • 跳过高频接口:健康检查、监控接口等高频接口建议跳过日志
  • 日志轮转使用文件输出时建议配合日志轮转工具如logrotate
  • 敏感信息:不要记录请求体和响应体,避免泄露敏感信息

4. Panic恢复

  • 放在最外层Recovery中间件应该放在中间件链的最前面
  • 记录日志务必配置logger确保panic信息被记录
  • 监控告警建议将panic事件接入监控系统及时发现问题
  • 堆栈跟踪:生产环境建议启用,方便排查问题

5. 限流配置

  • 合理设置阈值:根据实际业务需求设置限流阈值
  • 分布式部署当前实现使用内存存储适用于单机。分布式部署建议使用Redis
  • 键设计合理设计限流键可以按IP、用户、API等维度限流
  • 响应头客户端可以根据X-RateLimit-*响应头实现智能重试

6. 中间件顺序(推荐)

建议的中间件顺序(从外到内):

  1. Recovery - 最外层捕获所有panic
  2. Logging - 记录所有请求(包括限流的请求)
  3. RateLimit - 限流保护
  4. CORS - 处理跨域
  5. Timezone - 时区处理
  6. 业务中间件 - 认证、授权等
chain := middleware.NewChain(
    middleware.Recovery(recoveryConfig),    // 1. Panic恢复
    middleware.Logging(loggingConfig),      // 2. 日志记录
    middleware.RateLimit(rateLimitConfig),  // 3. 限流
    middleware.CORS(corsConfig),            // 4. CORS
    middleware.Timezone,                    // 5. 时区
)

7. 性能考虑

  • 异步日志使用异步logger避免IO阻塞
  • 限流算法:令牌桶算法支持突发流量
  • 自动清理:限流数据会自动清理,避免内存泄漏
  • 跳过路径合理使用SkipPaths减少不必要的处理

8. 生产环境建议

  • 使用异步logger配置日志文件和轮转
  • 启用Recovery中间件配置告警
  • 根据业务设置合理的限流阈值
  • 配置监控指标(请求量、错误率、限流触发次数等)
  • 定期review日志优化性能瓶颈