调整工具类的方法,优化方法调用及增加迁移工具及其用法
This commit is contained in:
154
examples/middleware_full_example.go
Normal file
154
examples/middleware_full_example.go
Normal file
@@ -0,0 +1,154 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"git.toowon.com/jimmy/go-common/config"
|
||||
commonhttp "git.toowon.com/jimmy/go-common/http"
|
||||
"git.toowon.com/jimmy/go-common/logger"
|
||||
"git.toowon.com/jimmy/go-common/middleware"
|
||||
)
|
||||
|
||||
// 示例:完整的中间件配置
|
||||
// 包括:Recovery、Logging、RateLimit、CORS、Timezone
|
||||
func main() {
|
||||
// 1. 配置logger(异步模式,输出到文件和stdout)
|
||||
loggerConfig := &logger.LoggerConfig{
|
||||
Level: "info",
|
||||
Output: "both", // 同时输出到stdout和文件
|
||||
FilePath: "./logs/app.log",
|
||||
Async: true, // 异步模式
|
||||
BufferSize: 1000, // 缓冲区大小
|
||||
Prefix: "[API]", // 日志前缀
|
||||
}
|
||||
myLogger, err := logger.NewLogger(loggerConfig)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to create logger:", 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"},
|
||||
ExposedHeaders: []string{"X-Total-Count"},
|
||||
AllowCredentials: false,
|
||||
MaxAge: 3600, // 1小时
|
||||
}
|
||||
|
||||
// 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{}) {
|
||||
// 使用统一的JSON响应格式
|
||||
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,
|
||||
"ip": r.RemoteAddr,
|
||||
}, "Rate limit exceeded")
|
||||
},
|
||||
}
|
||||
|
||||
// 6. 创建中间件链(顺序很重要!)
|
||||
// 顺序:Recovery -> Logging -> RateLimit -> CORS -> Timezone
|
||||
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. 定义路由
|
||||
mux := http.NewServeMux()
|
||||
|
||||
// API路由(应用所有中间件)
|
||||
mux.Handle("/api/hello", chain.ThenFunc(handleHello))
|
||||
mux.Handle("/api/panic", chain.ThenFunc(handlePanic)) // 测试panic恢复
|
||||
mux.Handle("/api/users", chain.ThenFunc(handleUsers))
|
||||
|
||||
// 健康检查(不应用中间件链,直接处理)
|
||||
mux.HandleFunc("/health", handleHealth)
|
||||
mux.HandleFunc("/metrics", handleMetrics)
|
||||
|
||||
// 8. 启动服务器
|
||||
addr := ":8080"
|
||||
log.Printf("Server starting on %s", addr)
|
||||
log.Printf("Try: http://localhost%s/api/hello", addr)
|
||||
log.Printf("Health: http://localhost%s/health", addr)
|
||||
|
||||
if err := http.ListenAndServe(addr, mux); err != nil {
|
||||
log.Fatal("Server failed:", err)
|
||||
}
|
||||
}
|
||||
|
||||
// handleHello 示例处理器:返回问候信息
|
||||
func handleHello(w http.ResponseWriter, r *http.Request) {
|
||||
h := commonhttp.NewHandler(w, r)
|
||||
|
||||
// 从Handler获取时区
|
||||
timezone := h.GetTimezone()
|
||||
|
||||
h.Success(map[string]interface{}{
|
||||
"message": "Hello, World!",
|
||||
"timezone": timezone,
|
||||
"method": r.Method,
|
||||
"path": r.URL.Path,
|
||||
})
|
||||
}
|
||||
|
||||
// handlePanic 示例处理器:测试panic恢复
|
||||
func handlePanic(w http.ResponseWriter, r *http.Request) {
|
||||
// 故意触发panic,测试Recovery中间件
|
||||
panic("This is a test panic!")
|
||||
}
|
||||
|
||||
// handleUsers 示例处理器:返回用户列表
|
||||
func handleUsers(w http.ResponseWriter, r *http.Request) {
|
||||
h := commonhttp.NewHandler(w, r)
|
||||
|
||||
// 模拟用户数据
|
||||
users := []map[string]interface{}{
|
||||
{"id": 1, "name": "Alice"},
|
||||
{"id": 2, "name": "Bob"},
|
||||
{"id": 3, "name": "Charlie"},
|
||||
}
|
||||
|
||||
h.Success(users)
|
||||
}
|
||||
|
||||
// handleHealth 健康检查处理器(不应用中间件)
|
||||
func handleHealth(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("OK"))
|
||||
}
|
||||
|
||||
// handleMetrics 监控指标处理器(不应用中间件)
|
||||
func handleMetrics(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("metrics: ok"))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user