# 中间件工具文档 ## 概述 中间件工具提供了常用的HTTP中间件功能,包括CORS处理、时区管理、请求日志、Panic恢复和限流等。 ## 功能特性 - **CORS中间件**:支持跨域资源共享配置 - **时区中间件**:从请求头读取时区信息,支持默认时区设置 - **日志中间件**:自动记录每个HTTP请求的详细信息 - **Recovery中间件**:捕获panic并恢复,防止服务崩溃 - **限流中间件**:基于令牌桶算法的请求限流 - **中间件链**:提供便捷的中间件链式调用 ## CORS中间件 ### 功能说明 CORS中间件用于处理跨域资源共享,支持: - 配置允许的源(支持通配符) - 配置允许的HTTP方法 - 配置允许的请求头 - 配置暴露的响应头 - 支持凭证传递 - 预检请求缓存时间设置 ### 使用方法 #### 基本使用(默认配置) ```go 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) } ``` #### 自定义配置 ```go 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) } ``` #### 允许所有源(开发环境) ```go 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. 如果 `AllowCredentials` 为 `true`,`AllowedOrigins` 不能使用 "*",必须指定具体的源 2. 通配符支持:`"*.example.com"` 会匹配 `"https://app.example.com"` 等子域名 3. 预检请求(OPTIONS)会自动处理,无需在业务代码中处理 ## 时区中间件 ### 功能说明 时区中间件用于从请求头读取时区信息,并存储到context中,方便后续使用。 - 从请求头 `X-Timezone` 读取时区 - 如果未传递时区信息,使用默认时区 `AsiaShanghai` - 时区信息存储到context中,可通过Handler的`GetTimezone()`方法获取 - 自动验证时区有效性,无效时区会回退到默认时区 ### 使用方法 #### 基本使用(默认时区 AsiaShanghai) ```go 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) } ``` #### 自定义默认时区 ```go 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) } ``` #### 在业务代码中使用时区 ```go 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) ```go 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 ```go 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 | 日志记录器 | 创建默认logger(stdout) | | 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错误响应 - 支持自定义错误处理 ### 使用方法 #### 基本使用(使用默认配置) ```go 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 ```go 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) } ``` #### 自定义错误响应 ```go 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请求/分钟) ```go 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) } ``` #### 自定义限流规则 ```go 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限流 ```go 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) } ``` #### 便捷函数 ```go // 按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. **算法选择**:使用令牌桶算法,支持突发流量 ## 中间件链 ### 功能说明 中间件链提供便捷的中间件组合方式,支持链式调用。 ### 使用方法 ```go 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) } ``` #### 链式追加中间件 ```go chain := middleware.NewChain(middleware.CORS()) chain.Append(middleware.Timezone) handler := chain.ThenFunc(handler) ``` ## 完整示例 ### 示例1:完整的生产级中间件配置 ```go 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 + 时区中间件 ```go 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:与路由框架集成 ```go 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. **业务中间件** - 认证、授权等 ```go 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日志,优化性能瓶颈