Skip to content

ミドルウェア

アーキテクチャ概要

このページは内蔵ミドルウェアのリファレンスです。Handler パイプラインの全体アーキテクチャ、オニオンモデルの原理、カスタムミドルウェアの作成については ハンドラパイプライン / Handler とミドルウェアチェーン を参照してください。

HTTPC はオニオンモデルのミドルウェアアーキテクチャを採用し、MiddlewareFunc を通じてリクエスト処理ロジックをラップします。

go
type MiddlewareFunc func(Handler) Handler
type Handler func(ctx context.Context, req RequestMutator) (ResponseMutator, error)

ミドルウェアは MiddlewareConfig.Middlewares で設定し、順番に実行されます:

go
client, _ := httpc.New(&httpc.Config{
    Middleware: &httpc.MiddlewareConfig{
        Middlewares: []httpc.MiddlewareFunc{
            httpc.RecoveryMiddleware(),
            httpc.LoggingMiddleware(log.Printf),
            httpc.RequestIDMiddleware("X-Request-ID", nil),
        },
    },
})

Chain

go
func Chain(middlewares ...MiddlewareFunc) MiddlewareFunc

複数のミドルウェアを単一のミドルウェアに組み合わせます。渡された順序で実行され、最後のミドルウェアの処理が終わると最終 Handler を呼び出します。

go
combined := httpc.Chain(
    httpc.RecoveryMiddleware(),
    httpc.LoggingMiddleware(log.Printf),
)

内蔵ミドルウェア

RecoveryMiddleware

go
func RecoveryMiddleware() MiddlewareFunc

panic リカバリミドルウェア。処理チェーン内の panic をキャッチし、スタック情報を含む error に変換して返します。

go
client, _ := httpc.New(&httpc.Config{
    Middleware: &httpc.MiddlewareConfig{
        Middlewares: []httpc.MiddlewareFunc{
            httpc.RecoveryMiddleware(),
        },
    },
})

LoggingMiddleware

go
func LoggingMiddleware(log func(format string, args ...any)) MiddlewareFunc

リクエストログミドルウェア。メソッド、URL、ステータスコード、所要時間を記録します。URL は自動的にマスクされます(認証情報を削除)。

go
client, _ := httpc.New(&httpc.Config{
    Middleware: &httpc.MiddlewareConfig{
        Middlewares: []httpc.MiddlewareFunc{
            httpc.LoggingMiddleware(log.Printf),
        },
    },
})
// 出力例:GET https://api.example.com/data -> 200 (125ms)

RequestIDMiddleware

go
func RequestIDMiddleware(headerName string, generator func() string) MiddlewareFunc

各リクエストにユニーク ID を追加します。デフォルトでは crypto/rand で 32 文字の 16 進数 ID を生成します。リクエストに同名のヘッダーが既に存在する場合は、元の値が保持され上書きされません。

パラメータ説明
headerNameヘッダー名(例:"X-Request-ID"
generatorカスタム ID 生成関数。nil を渡すとデフォルトの暗号セキュアジェネレーターを使用
go
// デフォルトジェネレーターを使用
middleware := httpc.RequestIDMiddleware("X-Request-ID", nil)

// カスタムジェネレーターを使用
middleware := httpc.RequestIDMiddleware("X-Request-ID", func() string {
    return uuid.New().String()
})

TIP

デフォルトジェネレーターは crypto/rand を使用しており、生成される ID は予測不可能なため、セキュリティが重要なシナリオに適しています。

TimeoutMiddleware

go
func TimeoutMiddleware(timeout time.Duration) MiddlewareFunc

ミドルウェアレベルのタイムアウト制御。クライアントの内蔵タイムアウトより前に有効になります。タイムアウト時にコンテキストをキャンセルし、エラーを返します。

Download やストリーミングリクエストには使用しないでください

TimeoutMiddlewaredefer cancel() は、ハンドラーが戻った(レスポンスヘッダーを受信した)直後に発火します。DownloadWithStreamBody リクエストでは、レスポンスボディを読み取る前にコンテキストがキャンセルされ、「context canceled」エラーとして現れます。ストリーミング/ダウンロードのシナリオでは WithTimeout を使用してください。

go
client, _ := httpc.New(&httpc.Config{
    Middleware: &httpc.MiddlewareConfig{
        Middlewares: []httpc.MiddlewareFunc{
            httpc.TimeoutMiddleware(10 * time.Second),
        },
    },
})

HeaderMiddleware

go
func HeaderMiddleware(headers map[string]string) MiddlewareFunc

各リクエストに静的ヘッダーを追加します。作成時にヘッダーのセキュリティ検証(CRLF インジェクション対策)を行います。リクエストに同名のヘッダーが既に存在する場合は競合により上書きされます。

go
client, _ := httpc.New(&httpc.Config{
    Middleware: &httpc.MiddlewareConfig{
        Middlewares: []httpc.MiddlewareFunc{
            httpc.HeaderMiddleware(map[string]string{
                "X-API-Version": "v2",
                "X-Client":      "myapp/1.0",
            }),
        },
    },
})

MetricsMiddleware

go
func MetricsMiddleware(onMetrics func(method, url string, statusCode int, duration time.Duration, err error)) MiddlewareFunc

メトリクス収集ミドルウェア。各リクエスト完了後にコールバックを呼び出し、メソッド、URL、ステータスコード、所要時間、エラー情報を渡します。

go
client, _ := httpc.New(&httpc.Config{
    Middleware: &httpc.MiddlewareConfig{
        Middlewares: []httpc.MiddlewareFunc{
            httpc.MetricsMiddleware(func(method, url string, status int, d time.Duration, err error) {
                metrics.Record(method, status, d, err)
            }),
        },
    },
})

AuditMiddleware

go
func AuditMiddleware(onAudit func(event AuditEvent)) MiddlewareFunc

セキュリティ監査ミドルウェア。金融、医療、行政などのコンプライアンスシナリオに適しています。デフォルトではリクエスト/レスポンスのメタ情報(メソッド、URL、ステータスコード、所要時間、リトライ回数など)を記録し、URL は自動的にマスクされます。完全なヘッダーを記録するには AuditMiddlewareWithConfig を使用し、IncludeHeaders: true を設定してください。

go
client, _ := httpc.New(&httpc.Config{
    Middleware: &httpc.MiddlewareConfig{
        Middlewares: []httpc.MiddlewareFunc{
            httpc.AuditMiddleware(func(event httpc.AuditEvent) {
                log.Printf("[AUDIT] %s %s -> %d (%v) user=%s ip=%s",
                    event.Method, event.URL, event.StatusCode,
                    event.Duration, event.UserID, event.SourceIP)
            }),
        },
    },
})

AuditMiddlewareWithConfig

go
func AuditMiddlewareWithConfig(onAudit func(event AuditEvent), config *AuditMiddlewareConfig) MiddlewareFunc

設定付きのセキュリティ監査ミドルウェア。

go
config := &httpc.AuditMiddlewareConfig{
    Format:         "json",
    IncludeHeaders: true,
    MaskHeaders:    []string{"Authorization", "Cookie"},
    SanitizeError:  true,
}

client, _ := httpc.New(&httpc.Config{
    Middleware: &httpc.MiddlewareConfig{
        Middlewares: []httpc.MiddlewareFunc{
            httpc.AuditMiddlewareWithConfig(func(event httpc.AuditEvent) {
                data, _ := json.Marshal(event)
                auditLog.Write(data)
            }, config),
        },
    },
})

監査タイプ

AuditEvent

go
type AuditEvent struct {
    Timestamp     time.Time           `json:"timestamp"`
    Method        string              `json:"method"`
    URL           string              `json:"url"`              // マスク済み(認証情報を削除)
    StatusCode    int                 `json:"statusCode"`
    Duration      time.Duration       `json:"duration"`
    Attempts      int                 `json:"attempts"`
    Error         error               `json:"error,omitempty"`
    SourceIP      string              `json:"sourceIP,omitempty"`
    UserID        string              `json:"userID,omitempty"`
    RedirectChain []string            `json:"redirectChain,omitempty"`
    ReqHeaders    map[string][]string `json:"reqHeaders,omitempty"`
    RespHeaders   map[string][]string `json:"respHeaders,omitempty"`
}

セキュリティ監査イベント。

MarshalJSON

go
func (e AuditEvent) MarshalJSON() ([]byte, error)

カスタム JSON シリアライズ。2 つの特別なフィールドを処理します:

フィールド変換ルール
DurationdurationMs(ミリ秒整数)を追加、元の duration フィールド(ナノ秒)を保持
Errorerror(エラーメッセージ文字列)に変換、nil の場合は省略
go
event := httpc.AuditEvent{
    Method:    "GET",
    URL:       "https://api.example.com/data",
    Duration:  150 * time.Millisecond,
    StatusCode: 200,
}
data, _ := json.Marshal(event)
// {"timestamp":"...","method":"GET","url":"...","statusCode":200,"duration":150000000,"attempts":0,"durationMs":150}

AuditMiddlewareConfig

go
type AuditMiddlewareConfig struct {
    Format         string   // "text"(デフォルト)または "json"
    IncludeHeaders bool     // リクエスト/レスポンスヘッダーを含むかどうか
    MaskHeaders    []string // マスクが必要なヘッダー名
    SanitizeError  bool     // エラー情報をマスクするかどうか
}
フィールドデフォルト説明
Format"text"出力形式
IncludeHeadersfalseヘッダーを記録するかどうか
MaskHeaders["Authorization", "Cookie", ...]標準的な機密ヘッダーリスト
SanitizeErrortrueエラー情報を [sanitized] に置換

DefaultAuditMiddlewareConfig

go
func DefaultAuditMiddlewareConfig() *AuditMiddlewareConfig

デフォルトの監査設定を返します。

監査コンテキストキー

リクエストコンテキストで監査情報を渡します:

go
// ソース IP を設定
ctx = context.WithValue(ctx, httpc.SourceIPKey, "192.168.1.1")

// ユーザー ID を設定
ctx = context.WithValue(ctx, httpc.UserIDKey, "user-123")

result, err := client.Request(ctx, "GET", url)
定数タイプ説明
SourceIPKeyauditContextKeyソース IP コンテキストキー
UserIDKeyauditContextKeyユーザー識別コンテキストキー

関連項目