sync from project

This commit is contained in:
2025-06-18 10:12:19 +08:00
parent 61ffeeb3b8
commit fb579e8689
20 changed files with 1332 additions and 103 deletions

View File

@ -42,3 +42,20 @@ func DebugPanicHandler(w http.ResponseWriter, r *http.Request, err any) {
func Debug() middleware.Middleware {
return Recover(DebugPanicHandler)
}
// ProductionPanicHandler is a PanicResponseFunc that provides a generic error message
// in production environments and logs the detailed panic error.
func ProductionPanicHandler(w http.ResponseWriter, r *http.Request, err any) {
httplog.Logger(r).With("panic", err).Error("request panicked")
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]any{
"error": "Internal Server Error",
})
}
// Production returns a middleware that recovers from panics and handles them
// with ProductionPanicHandler.
func Production() middleware.Middleware {
return Recover(ProductionPanicHandler)
}

View File

@ -0,0 +1,56 @@
package recover
import (
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
)
func panicHandler(w http.ResponseWriter, r *http.Request) {
panic("test panic")
}
func TestDebugRecover(t *testing.T) {
handler := http.HandlerFunc(panicHandler)
wrappedHandler := Debug().WrapHandler(handler)
req := httptest.NewRequest("GET", "/panic", nil)
rr := httptest.NewRecorder()
wrappedHandler.ServeHTTP(rr, req)
if rr.Code != http.StatusInternalServerError {
t.Errorf("expected status %d, got %d", http.StatusInternalServerError, rr.Code)
}
var resp map[string]any
if err := json.Unmarshal(rr.Body.Bytes(), &resp); err != nil {
t.Fatalf("failed to unmarshal response body: %v", err)
}
if resp["error"] != "test panic" {
t.Errorf("expected error 'test panic', got '%v'", resp["error"])
}
}
func TestProductionRecover(t *testing.T) {
handler := http.HandlerFunc(panicHandler)
wrappedHandler := Production().WrapHandler(handler)
req := httptest.NewRequest("GET", "/panic", nil)
rr := httptest.NewRecorder()
wrappedHandler.ServeHTTP(rr, req)
if rr.Code != http.StatusInternalServerError {
t.Errorf("expected status %d, got %d", http.StatusInternalServerError, rr.Code)
}
var resp map[string]any
if err := json.Unmarshal(rr.Body.Bytes(), &resp); err != nil {
t.Fatalf("failed to unmarshal response body: %v", err)
}
if resp["error"] != "Internal Server Error" {
t.Errorf("expected error 'Internal Server Error', got '%v'", resp["error"])
}
}