인터페이스 정의
Client
type Client interface {
Doer
// HTTP 메서드
Get(url string, options ...RequestOption) (*Result, error)
Post(url string, options ...RequestOption) (*Result, error)
Put(url string, options ...RequestOption) (*Result, error)
Patch(url string, options ...RequestOption) (*Result, error)
Delete(url string, options ...RequestOption) (*Result, error)
Head(url string, options ...RequestOption) (*Result, error)
Options(url string, options ...RequestOption) (*Result, error)
// 파일 다운로드
Download(ctx context.Context, url string, cfg *DownloadConfig, options ...RequestOption) (*DownloadResult, error)
// 수명 주기
Close() error
}메인 클라이언트 인터페이스로, New()로 생성합니다. 자세한 내용은 패키지 함수와 클라이언트 메서드를 참조하세요.
Doer
type Doer interface {
Request(ctx context.Context, method, url string, options ...RequestOption) (*Result, error)
}최소 인터페이스로, 핵심 Request 메서드만 포함합니다. 커스텀 구현에 적합합니다.
type MyDoer struct{}
func (d *MyDoer) Request(ctx context.Context, method, url string, options ...httpc.RequestOption) (*httpc.Result, error) {
// 커스텀 구현
return nil, nil
}DomainClienter
type DomainClienter interface {
Client
// URL 접근
URL() string
Domain() string
// 세션 헤더 관리
SetHeader(key, value string) error
SetHeaders(headers map[string]string) error
DeleteHeader(key string)
ClearHeaders()
GetHeaders() map[string]string
// 세션 Cookie 관리
SetCookie(cookie *http.Cookie) error
SetCookies(cookies []*http.Cookie) error
DeleteCookie(name string)
ClearCookies()
GetCookies() []*http.Cookie
GetCookie(name string) *http.Cookie
// 세션 접근
Session() *SessionManager
}도메인 범위 클라이언트로, Cookie 와 요청 헤더를 자동으로 관리합니다. 자세한 내용은 도메인 클라이언트와 세션 관리를 참조하세요.
RetryPolicy
type RetryPolicy interface {
ShouldRetry(resp ResponseReader, err error, attempt int) bool
GetDelay(attempt int) time.Duration
MaxRetries() int
}커스텀 재시도 전략 인터페이스입니다.
| 메서드 | 설명 |
|---|---|
ShouldRetry(resp, err, attempt) | 재시도 여부 판단, attempt는 0 부터 시작 |
GetDelay(attempt) | 다음 재시도 전 대기 시간 반환 |
MaxRetries() | 최대 재시도 횟수 반환 |
내부 타입 제한
ShouldRetry 의 resp 매개변수 타입 ResponseReader 는 내부 인터페이스 (internal/types 패키지에 위치) 이므로 외부 코드에서 직접 참조할 수 없습니다. 따라서 RetryPolicy는 같은 모듈 내에서만 구현할 수 있습니다. 대부분의 시나리오는 RetryConfig 설정과 WithMaxRetries 옵션으로 재시도 요구사항을 충족할 수 있습니다. 커스텀 전략이 필요한 경우 프로젝트 내부 패키지에서 RetryPolicy 인터페이스를 구현하세요.
다음 예제는 RetryPolicy의 구현 패턴을 보여줍니다. ResponseReader 는 내부 타입이므로 이 코드는 httpc 모듈 내부에서만 컴파일됩니다:
// 주의: ResponseReader 는 내부 타입 (internal/types 패키지) 입니다.
// 이 코드는 httpc 모듈 외부에서 컴파일할 수 없습니다.
// 대부분의 사용자는 RetryConfig 와 WithMaxRetries 로 재시도를 설정해야 합니다.
type MyRetryPolicy struct {
maxRetries int
}
func (p *MyRetryPolicy) ShouldRetry(resp ResponseReader, err error, attempt int) bool {
if attempt >= p.maxRetries {
return false
}
if err != nil {
return true
}
return resp.StatusCode() >= 500
}
func (p *MyRetryPolicy) GetDelay(attempt int) time.Duration {
return time.Second * time.Duration(1<<attempt)
}
func (p *MyRetryPolicy) MaxRetries() int {
return p.maxRetries
}핵심 타입
RequestMutator
type RequestMutator interface {
// 읽기 메서드
Method() string
URL() string
Headers() map[string]string
QueryParams() map[string]any
Body() any
Timeout() time.Duration
MaxRetries() int
Context() context.Context
Cookies() []http.Cookie
FollowRedirects() *bool
MaxRedirects() *int
StreamBody() bool
// 쓰기 메서드
SetMethod(string)
SetURL(string)
SetHeaders(map[string]string)
SetHeader(key, value string)
SetQueryParams(map[string]any)
SetBody(any)
SetTimeout(time.Duration)
SetMaxRetries(int)
SetContext(context.Context)
SetCookies([]http.Cookie)
SetFollowRedirects(*bool)
SetMaxRedirects(*int)
SetStreamBody(bool)
}미들웨어에서 사용하며, 요청에 대한 읽기/쓰기 접근을 제공합니다. 내부 인터페이스 RequestReader 와 RequestWriter 로 구성됩니다. 전체 메서드 계약과 읽기/쓰기 예제는 요청과 응답 뮤테이터를 참조하세요.
ResponseMutator
type ResponseMutator interface {
// 읽기 메서드
StatusCode() int
Status() string
Proto() string
Headers() http.Header
Body() string
RawBody() []byte
ContentLength() int64
Duration() time.Duration
Attempts() int
Cookies() []*http.Cookie
RedirectChain() []string
RedirectCount() int
RequestHeaders() http.Header
RequestURL() string
RequestMethod() string
// 쓰기 메서드
SetStatusCode(int)
SetStatus(string)
SetProto(string)
SetHeaders(http.Header)
SetBody(string)
SetRawBody([]byte)
SetContentLength(int64)
SetDuration(time.Duration)
SetAttempts(int)
SetCookies([]*http.Cookie)
SetRedirectChain([]string)
SetRedirectCount(int)
SetRequestHeaders(http.Header)
SetRequestURL(string)
SetRequestMethod(string)
SetHeader(key string, values ...string)
}미들웨어에서 사용하며, 응답에 대한 읽기/쓰기 접근을 제공합니다. 내부 인터페이스 ResponseReader 와 ResponseWriter 로 구성됩니다. 전체 메서드 계약은 요청과 응답 뮤테이터를 참조하세요.
Handler
type Handler func(ctx context.Context, req RequestMutator) (ResponseMutator, error)요청 처리 함수 서명입니다.
MiddlewareFunc
type MiddlewareFunc func(Handler) Handler미들웨어 함수 서명으로, 다음 Handler 를 받아 래핑된 Handler 를 반환합니다.
인증서 고정
인증서 고정 (Certificate Pinning) 은 TLS 핸드셰이크 단계에서 서버 인증서가 사전에 고정된 공개키/인증서와 일치하는지 검증합니다. 신뢰할 수 있는 CA 가 침해되더라도 핸드셰이크가 거부되어 중간자 공격을 방어할 수 있습니다.
CertificatePinner
type CertificatePinner = security.CertificatePinner인증서 고정기 인터페이스. 아래 생성자로 생성한 후 SecurityConfig.CertificatePinner 필드 (Config.Security로 접근) 에 할당합니다:
pinner, err := httpc.NewSPKIHashPinner(
"YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2fuihg=", // 현재 키
"C5+lpZ7tcVwmwQIMcRtPbsQtWLABXhQzejna0wHFr8M=", // 백업 키 (로테이션)
)
if err != nil {
log.Fatal(err)
}
cfg := httpc.DefaultConfig()
cfg.Security.CertificatePinner = pinner
client, err := httpc.New(cfg)TIP
Pinner 구현은 동시에 안전하므로 동일한 Config로 생성된 여러 클라이언트가 공유할 수 있습니다 (딥 카피 시 참조로 전달되며 복제되지 않음). 고급 사용자는 이 인터페이스를 직접 구현하여 커스텀 고정 전략 (예: 공개키 대신 전체 인증서 고정) 을 지원할 수도 있습니다.
NewSPKIHashPinner
func NewSPKIHashPinner(hashes ...string) (CertificatePinner, error)하나 이상의 base64 인코딩된 SHA-256 해시 값 (DER 인코딩된 SubjectPublicKeyInfo/SPKI에 대한) 으로 인증서 고정기를 생성합니다. 이는 가장 널리 사용되는 고정 형식 (HPKP 가 채택) 이며 권장되는 방식입니다.
여러 해시를 전달하면 키 로테이션을 지원합니다 — 대상 공개키가 고정된 해시 중 어느 하나와 일치하기만 하면 핸드셰이크가 성공합니다.
다음 명령으로 인증서에서 해시를 생성합니다:
openssl x509 -in cert.pem -pubkey -noout | openssl pkey -pubin -outform der \
| openssl dgst -sha256 -binary | openssl enc -base64유효한 해시가 제공되지 않았거나, 해시가 유효한 base64 가 아닌 경우 오류를 반환합니다.
NewPublicKeyPinner
func NewPublicKeyPinner(publicKeys ...[]byte) (CertificatePinner, error)하나 이상의 DER 인코딩된 PKIX 공개키 (x509.MarshalPKIXPublicKey가 반환) 로 인증서 고정기를 생성합니다. 내부적으로 각 공개키에 대해 SHA-256 해시를 계산합니다; 원본 공개키 바이트를 이미 보유하고 있다면 NewSPKIHashPinner보다 편리한 선택입니다.
유효한 공개키가 제공되지 않은 경우 오류를 반환합니다.
NewCertificatePinnerChain
func NewCertificatePinnerChain(pinners ...CertificatePinner) CertificatePinner여러 고정기를 하나로 조합합니다. 래핑된 고정기 중 어느 하나라도 해당 인증서를 수락하면 인증서가 수락됩니다. 여러 고정 전략을 동시에 지원하거나, 서로 다른 생성자로 구축한 로테이션 키를 조합할 때 사용합니다.
인수 없음 동작: 모든 인증서 허용
인수를 전달하지 않으면 빈 체인을 반환하며, 이 체인은 어떤 인증서도 검증하지 않습니다 (검증 로직이 직접 nil을 반환합니다) — 즉 모든 인증서를 허용하며, 인증서 고정을 비활성화한 것과 동일합니다 (소스 코드 internal/security/certpin.go의 주석은 "No pinners means no pinning"). 이는 "pinner 가 없으면 거부한다"는 직관과 반대되는 fail-open 동작입니다. 항상 최소 하나의 유효한 pinner 를 전달하고, 인수 없음 동작에 의존하지 마세요.
더 읽어보기
인증서 고정의 완전한 가이드 (해시 생성, 키 로테이션 전략, 프로덕션 배포) 는 TLS 인증서 고정을 참조하세요.
관련 페이지
| 타입 | 상세 참조 |
|---|---|
Result / RequestInfo / ResponseInfo / RequestMeta | Result |
SessionManager 메서드 | 세션 관리 |
DomainClient 구현 | 도메인 클라이언트 |
DownloadConfig / DownloadResult | 파일 다운로드 |
ClientError / ErrorType / 오류 변수 | 오류 타입 |
FormData / FileData / BodyKind | 상수와 타입 |