미들웨어 체인
양파 모델
HTTPC 미들웨어는 양파 모델을 채택하여, 요청은 외부에서 내부로, 응답은 내부에서 외부로 흐릅니다:
text
요청 → Recovery → Logging → RequestID → Handler
↓
응답 ← Recovery ← Logging ← RequestID ← Responsego
cfg := httpc.DefaultConfig()
cfg.Middleware.Middlewares = []httpc.MiddlewareFunc{
httpc.RecoveryMiddleware(), // 가장 바깥: panic 복구
httpc.LoggingMiddleware(&httpc.LoggingConfig{LogFunc: log.Printf}), // 두 번째: 로그 기록
httpc.RequestIDMiddleware(httpc.DefaultRequestIDConfig()), // 가장 안쪽: 요청 ID
}
client, err := httpc.New(cfg)
if err != nil {
log.Fatal(err)
}
defer client.Close()내장 미들웨어
RecoveryMiddleware
panic 복구, 프로세스 크래시 방지:
go
httpc.RecoveryMiddleware()LoggingMiddleware
요청/응답 로그, URL 자동 마스킹:
go
httpc.LoggingMiddleware(&httpc.LoggingConfig{LogFunc: func(format string, args ...any) {
log.Printf("[HTTP] "+format, args...)
}})
// 출력 예시: [HTTP] GET https://api.example.com/data -> 200 (150ms)(상태 코드와 소요 시간은 실측값이며 고정값이 아님)RequestIDMiddleware
각 요청에 고유 ID 추가, crypto/rand로 생성:
go
httpc.RequestIDMiddleware(httpc.DefaultRequestIDConfig()) // 기본 32 자 hex
// 커스텀 생성기
httpc.RequestIDMiddleware(&httpc.RequestIDConfig{
HeaderName: "X-Request-ID",
Generator: func() string {
return uuid.New().String()
},
})TimeoutMiddleware
미들웨어 계층 타임아웃, 클라이언트 타임아웃 전에 강제 실행:
go
httpc.TimeoutMiddleware(&httpc.TimeoutMiddlewareConfig{Duration: 30 * time.Second})Download 나 스트리밍 요청에는 사용 금지
TimeoutMiddleware의 defer cancel()은 핸들러가 반환 (응답 헤더 수신) 된 직후에 실행되어, Download나 WithStreamBody 요청에서는 응답 본문을 읽기 전에 컨텍스트가 미리 취소되어 "context canceled" 오류가 발생합니다. 스트리밍/다운로드 시나리오에서는 WithTimeout 옵션을 대신 사용하세요.
HeaderMiddleware
모든 요청에 정적 헤더 추가:
go
httpc.HeaderMiddleware(&httpc.HeaderConfig{Headers: map[string]string{
"X-App-Version": "1.0.0",
"X-Platform": "server",
}})MetricsMiddleware
요청 메트릭 수집:
go
httpc.MetricsMiddleware(&httpc.MetricsConfig{OnMetrics: func(method, url string, statusCode int, duration time.Duration, err error) {
metrics.IncrCounter("http.requests", 1)
metrics.RecordTimer("http.latency", duration)
if err != nil {
metrics.IncrCounter("http.errors", 1)
}
}})AuditMiddleware
보안 감사, 금융, 의료 등 컴플라이언스 시나리오에 적합:
go
auditCfg := httpc.DefaultAuditConfig()
auditCfg.OnAudit = func(event httpc.AuditEvent) {
log.Printf("[AUDIT] %s %s -> %d (%v)",
event.Method, event.URL, event.StatusCode, event.Duration)
}
httpc.AuditMiddleware(auditCfg)감사 옵션 설정
DefaultAuditConfig()로 기본 설정을 가져온 뒤 필드를 수정하여 출력 형식, 헤더 기록 및 마스킹을 제어할 수 있습니다:
go
auditCfg := httpc.DefaultAuditConfig()
auditCfg.Format = "json"
auditCfg.IncludeHeaders = true
auditCfg.MaskHeaders = []string{"Authorization", "Cookie"}
auditCfg.SanitizeError = true
auditCfg.OnAudit = func(event httpc.AuditEvent) {
data, err := json.Marshal(event)
if err != nil {
log.Println("감사 이벤트 직렬화 실패:", err)
return
}
log.Println(string(data))
}
httpc.AuditMiddleware(auditCfg)감사 이벤트는 컨텍스트에서 SourceIP 와 UserID 추출을 지원합니다:
go
ctx := context.WithValue(context.Background(), httpc.SourceIPKey, "192.168.1.1")
ctx = context.WithValue(ctx, httpc.UserIDKey, "user-123")수동 체인 조합
Chain 함수로 미들웨어를 조합합니다:
go
middleware := httpc.Chain(
httpc.RecoveryMiddleware(),
httpc.LoggingMiddleware(&httpc.LoggingConfig{LogFunc: log.Printf}),
httpc.RequestIDMiddleware(httpc.DefaultRequestIDConfig()),
)
cfg := httpc.DefaultConfig()
cfg.Middleware.Middlewares = []httpc.MiddlewareFunc{middleware}커스텀 미들웨어
go
func CORSMiddleware(origin string) httpc.MiddlewareFunc {
return func(next httpc.Handler) httpc.Handler {
return func(ctx context.Context, req httpc.RequestMutator) (httpc.ResponseMutator, error) {
// 요청 단계: 요청 수정
req.SetHeader("Origin", origin)
// 다음 핸들러 호출
resp, err := next(ctx, req)
// 응답 단계: 기록 또는 응답 수정
if resp != nil {
log.Printf("응답 상태: %d", resp.StatusCode())
}
return resp, err
}
}
}단락 미들웨어
go
func CircuitBreakerMiddleware(threshold int) httpc.MiddlewareFunc {
var failures int
var mu sync.Mutex
return func(next httpc.Handler) httpc.Handler {
return func(ctx context.Context, req httpc.RequestMutator) (httpc.ResponseMutator, error) {
mu.Lock()
if failures >= threshold {
mu.Unlock()
return nil, fmt.Errorf("circuit breaker open")
}
mu.Unlock()
resp, err := next(ctx, req)
if err != nil {
mu.Lock()
failures++
mu.Unlock()
}
return resp, err
}
}
}미들웨어 설정
go
cfg := httpc.DefaultConfig()
cfg.Middleware.Middlewares = []httpc.MiddlewareFunc{
httpc.RecoveryMiddleware(),
httpc.LoggingMiddleware(&httpc.LoggingConfig{LogFunc: log.Printf}),
}
cfg.Defaults.UserAgent = "my-app/1.0"
cfg.Defaults.Headers = map[string]string{"X-App": "my-app"}
cfg.Defaults.FollowRedirects = true
cfg.Defaults.MaxRedirects = 10
client, err := httpc.New(cfg)
if err != nil {
log.Fatal(err)
}
defer client.Close()다음 단계
- 미들웨어 API - 완전한 미들웨어 참조
- 재시도와 장애 허용 - 재시도 전략 가이드
- 보안 개요 - 감사 미들웨어 보안 실천