package middleware import ( "fmt" "net/http" "runtime/debug" commonhttp "git.toowon.com/jimmy/go-common/http" "git.toowon.com/jimmy/go-common/i18n" "git.toowon.com/jimmy/go-common/logger" ) // RecoveryConfig Recovery 中间件配置 type RecoveryConfig struct { Logger *logger.Logger I18n *i18n.I18n } // Recovery Panic 恢复中间件,响应统一 JSON 200 + system.internal_error func Recovery(config *RecoveryConfig) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer func() { if err := recover(); err != nil { fields := map[string]any{ "method": r.Method, "path": r.URL.Path, "error": fmt.Sprintf("%v", err), "stack": string(debug.Stack()), } log := logger.FromContextWithLogger(r.Context(), nil) if config != nil && config.Logger != nil { log = logger.FromContextWithLogger(r.Context(), config.Logger) } log.Error("panic recovered", fields) h := commonhttp.NewHandler(w, r) if config != nil && config.I18n != nil { h = commonhttp.NewHandler(w, r, commonhttp.WithI18n(config.I18n)) } h.Error("system.internal_error") } }() next.ServeHTTP(w, r) }) } }