Documentation
¶
Index ¶
- Constants
- Variables
- func CheckResponseStatus(resp *http.Response, allowedStatusCodes ...int) error
- func CheckResponseStatusWithoutReconstruct(resp *http.Response, allowedStatusCodes ...int) error
- func Get(ctx context.Context, f Fetcher, url string) (*http.Response, error)
- type Config
- type Fetcher
- func New(maxRetries int, minRetryDelay time.Duration, maxBytes int64, opts ...Option) Fetcher
- func NewFromConfig(cfg Config, opts ...Option) Fetcher
- func NewMaxBytesFetcher(delegate Fetcher, limit int64) Fetcher
- func NewMimeTypeFetcher(delegate Fetcher, allowedMimeTypes []string, allowMissingContentType bool) Fetcher
- type HTTPFetcher
- type HTTPStatusError
- type LoggingFetcher
- type MaxBytesFetcher
- type MimeTypeFetcher
- type Option
- func WithCookieJar(jar http.CookieJar) Option
- func WithDisableTransportCaching(disable bool) Option
- func WithIdleConnTimeout(timeout time.Duration) Option
- func WithMaxConnsPerHost(max int) Option
- func WithMaxIdleConns(max int) Option
- func WithMaxIdleConnsPerHost(max int) Option
- func WithMaxRedirects(max int) Option
- func WithProxy(proxyURL string) Option
- func WithResponseHeaderTimeout(timeout time.Duration) Option
- func WithTLSHandshakeTimeout(timeout time.Duration) Option
- func WithTimeout(timeout time.Duration) Option
- func WithTransport(transport http.RoundTripper) Option
- func WithUserAgent(ua string) Option
- type RetryFetcher
- type StatusCodeFetcher
- type UserAgentFetcher
Constants ¶
const (
// NoLimit 응답 본문의 크기 제한을 적용하지 않음을 나타내는 값입니다.
NoLimit = -1
)
const ( // NoProxy 프록시를 명시적으로 비활성화하는 특수 상수입니다. // WithProxy(NoProxy) 호출 시 환경 변수를 무시하고 직접 연결합니다. NoProxy = "DIRECT" )
Variables ¶
var ErrMaxRetriesExceeded = apperrors.New(apperrors.Unavailable, "최대 재시도 횟수를 초과하여 요청 처리에 실패했습니다")
ErrMaxRetriesExceeded 최대 재시도 횟수 초과 시 반환하는 에러입니다.
var ErrMissingResponseContentType = apperrors.New(apperrors.InvalidInput, "Content-Type 헤더가 누락되어 요청을 처리할 수 없습니다")
ErrMissingResponseContentType Content-Type 헤더가 누락된 경우 반환하는 에러입니다.
var ErrUnsupportedTransport = apperrors.New(apperrors.Internal, "지원하지 않는 Transport 형식입니다: 표준 *http.Transport 타입만 설정을 적용할 수 있습니다")
ErrUnsupportedTransport 사용자가 제공한 Transport가 표준 *http.Transport 타입이 아닐 때 반환하는 에러입니다.
Functions ¶
func CheckResponseStatus ¶
CheckResponseStatus HTTP 응답의 상태 코드를 검증하고, 실패 시 구조화된 에러를 반환합니다.
목적 ¶
HTTP 응답 상태 코드를 검사하여 성공/실패를 판단하고, 실패한 경우 상태 코드에 맞는 도메인 에러 타입(apperrors.ErrorType)으로 변환하여 HTTPStatusError를 생성합니다.
사용 예시 ¶
resp, _ := http.Get("https://api.example.com/users")
if err := CheckResponseStatus(resp); err != nil {
var statusErr *HTTPStatusError
if errors.As(err, &statusErr) {
log.Error("API 호출 실패", "status", statusErr.StatusCode, "body", statusErr.BodySnippet)
}
}
매개변수:
- resp: 검증할 HTTP 응답 객체
- allowedStatusCodes: 허용할 상태 코드 목록 (비어있으면 200 OK만 허용)
반환값:
- 상태 코드가 허용되면 nil, 그렇지 않으면 HTTPStatusError
주의사항:
- 이 함수는 응답 객체의 Body를 재구성하므로, 호출 후에도 Body를 읽을 수 있습니다.
- Body를 즉시 닫을 예정이라면 CheckResponseStatusWithoutReconstruct를 사용하세요.
func CheckResponseStatusWithoutReconstruct ¶
CheckResponseStatusWithoutReconstruct HTTP 응답의 상태 코드를 검증하고, 실패 시 Body 재구성 없이 구조화된 에러를 반환합니다.
목적 ¶
CheckResponseStatus와 동일한 검증을 수행하지만, 응답 객체의 Body를 재구성하지 않습니다. 에러 발생 시 즉시 Body를 닫을 계획이 있는 경우 이 함수를 사용하면 불필요한 Body 재구성 오버헤드를 피할 수 있습니다.
사용 시나리오 ¶
- StatusCodeFetcher처럼 에러 발생 시 즉시 drainAndCloseBody()를 호출하는 경우
- Body 내용을 다시 읽을 필요가 없는 경우
- 성능 최적화가 중요한 경우
사용 예시 ¶
resp, _ := fetcher.Do(req)
if err := CheckResponseStatusWithoutReconstruct(resp, 200, 201); err != nil {
drainAndCloseBody(resp.Body) // Body를 즉시 닫음
return nil, err
}
매개변수:
- resp: 검증할 HTTP 응답 객체
- allowedStatusCodes: 허용할 상태 코드 목록
반환값:
- 상태 코드가 허용되면 nil, 그렇지 않으면 HTTPStatusError
주의사항:
- 이 함수 호출 후 resp.Body는 일부가 읽힌 상태이므로, 에러 시 Body를 즉시 닫아야 합니다.
func Get ¶
Get 지정된 URL로 HTTP GET 요청을 전송하는 헬퍼 함수입니다.
이 함수는 Fetcher 인터페이스의 모든 구현체에서 공통으로 사용할 수 있으며, http.Request 객체를 직접 생성하는 번거로움을 줄여줍니다.
매개변수:
- ctx: 요청의 생명주기를 제어하는 Context (타임아웃, 취소 등)
- f: HTTP 요청을 실제로 수행할 Fetcher 구현체
- url: GET 요청을 보낼 URL (유효한 HTTP/HTTPS URL이어야 함)
반환값:
- *http.Response: 성공 시 HTTP 응답 객체 (Body는 호출자가 반드시 닫아야 함)
- error: URL 파싱 실패, 네트워크 오류, HTTP 에러 등
에러 처리:
- URL이 잘못된 경우 즉시 에러를 반환합니다.
- 요청 실패 시 커넥션 재사용을 위해 응답 객체의 Body를 자동으로 읽어서 버리고 닫습니다.
Types ¶
type Config ¶
type Config struct {
// ProxyURL 프록시 URL입니다.
//
// 설정 규칙:
// - nil: 기본 설정을 따릅니다.
// · 일반적인 경우: 환경 변수(HTTP_PROXY, HTTPS_PROXY)를 사용합니다.
// · HTTP 클라이언트를 직접 주입한 경우: 해당 클라이언트의 기존 Proxy 정책을 그대로 유지합니다.
// - URL: 지정된 프록시 서버 사용 (예: "http://proxy:8080")
// - NoProxy(또는 "DIRECT") 또는 빈 문자열(""): 프록시 비활성화 (환경 변수 무시, 직접 연결)
ProxyURL *string
// MaxRedirects HTTP 클라이언트의 최대 리다이렉트(3xx) 횟수입니다.
//
// 설정 규칙:
// - nil: 설정하지 않음 (HTTPFetcher 기본값 사용)
// - 0: 리다이렉트 허용 안 함
// - 양수: 지정된 횟수만큼 리다이렉트 허용
// - 음수: 기본값으로 보정
MaxRedirects *int
// EnableUserAgentRandomization 요청마다 User-Agent를 랜덤으로 변경할지 여부를 제어합니다.
//
// 설정 값:
// - false (기본값): 기능 비활성화 (원본 요청의 User-Agent 사용)
// - true: 기능 활성화 (UserAgents 또는 내장 목록에서 랜덤 선택, 봇 차단 우회에 유용)
EnableUserAgentRandomization bool
// UserAgents User-Agent를 랜덤으로 선택하여 주입할 때 사용할 User-Agent 문자열 목록입니다.
//
// 설정 값:
// - nil/빈 슬라이스: 내장된 User-Agent 목록에서 랜덤으로 선택하여 주입
// - 값 지정: 지정된 목록에서 랜덤으로 선택하여 주입
UserAgents []string
// MaxIdleConns 전체 유휴 연결의 최대 개수입니다.
// 모든 호스트에 대해 유지할 수 있는 유휴 연결의 최대 개수를 제한합니다.
//
// 설정 규칙:
// - nil: 설정하지 않음 (HTTPFetcher 기본값 사용)
// - 0: 무제한
// - 양수: 지정된 개수로 제한
// - 음수: 기본값으로 보정
MaxIdleConns *int
// MaxIdleConnsPerHost 호스트당 유휴 연결의 최대 개수입니다.
//
// 설정 규칙:
// - nil: 설정하지 않음 (HTTPFetcher 기본값 사용)
// - 0: net/http가 기본값 2로 해석
// - 양수: 지정된 개수로 제한
// - 음수: 기본값으로 보정
MaxIdleConnsPerHost *int
// MaxConnsPerHost 호스트당 최대 연결 개수입니다.
// 동일한 호스트에 대해 동시에 유지할 수 있는 최대 연결 개수를 제한합니다.
//
// 설정 규칙:
// - nil: 설정하지 않음 (HTTPFetcher 기본값 사용)
// - 0: 무제한
// - 양수: 지정된 개수로 제한
// - 음수: 기본값으로 보정
MaxConnsPerHost *int
// Timeout HTTP 요청 전체에 대한 타임아웃입니다.
// 요청 전송부터 응답 본문(Body)까지 모두 읽는 전체 과정에 대한 제한 시간입니다.
//
// 설정 규칙:
// - nil: 설정하지 않음 (HTTPFetcher 기본값 사용)
// - 0: 타임아웃 없음 (무한 대기)
// - 양수: 지정된 시간으로 제한
// - 음수: 기본값으로 보정
Timeout *time.Duration
// TLSHandshakeTimeout TLS 핸드셰이크 타임아웃입니다.
// TLS 연결 수립 과정에서 핸드셰이크가 완료되기까지 허용되는 최대 시간입니다.
//
// 설정 규칙:
// - nil: 설정하지 않음 (HTTPFetcher 기본값 사용)
// - 0: 타임아웃 없음 (무한 대기)
// - 양수: 지정된 시간으로 제한
// - 음수: 기본값으로 보정
TLSHandshakeTimeout *time.Duration
// ResponseHeaderTimeout HTTP 응답 헤더 대기 타임아웃입니다.
// 요청 전송 후 서버로부터 응답 헤더를 받을 때까지 허용되는 최대 시간입니다.
// 본문(Body) 데이터 수신 시간은 포함되지 않습니다.
//
// 설정 규칙:
// - nil: 설정하지 않음 (HTTPFetcher 기본값 사용)
// - 0: 타임아웃 없음 (무한 대기)
// - 양수: 지정된 시간으로 제한
// - 음수: 타임아웃 없음(0)으로 보정
ResponseHeaderTimeout *time.Duration
// IdleConnTimeout 유휴 연결 타임아웃입니다.
// 연결 풀에서 사용되지 않는 연결이 닫히기 전까지 유지되는 최대 시간입니다.
//
// 설정 규칙:
// - nil: 설정하지 않음 (HTTPFetcher 기본값 사용)
// - 0: 제한 없음 (연결 무기한 유지)
// - 양수: 지정된 시간 후 유휴 연결 종료
// - 음수: 기본값으로 보정
IdleConnTimeout *time.Duration
// MaxRetries 최대 재시도 횟수입니다.
//
// 설정 규칙:
// - nil: 기본값으로 보정
// - 0: 재시도 안 함
// - 양수: 실패 시(5xx 에러 또는 네트워크 오류 등) 지정된 횟수만큼 재시도
// - 보정: 최소값(minAllowedRetries) 미만은 최소값으로, 최대값(maxAllowedRetries) 초과는 최대값으로 보정
MaxRetries *int
// MinRetryDelay 재시도 대기 시간의 최소값입니다.
//
// 설정 규칙:
// - nil: 기본값으로 보정
// - 1초 미만: 서버 부하 방지를 위해 최소 시간(1초)으로 보정
// - 1초 이상: 별도의 보정 없이 설정값을 그대로 적용
MinRetryDelay *time.Duration
// MaxRetryDelay 재시도 대기 시간의 최대값입니다.
//
// 설정 규칙:
// - nil: 기본값으로 보정
// - 0: 기본값으로 보정
// - MinRetryDelay 미만: 최대 재시도 대기 시간은 최소 재시도 대기 시간보다 작을 수 없으므로 MinRetryDelay로 보정
// - 그 외: 지수 백오프가 진행되더라도 재시도 대기 시간이 이 설정값을 초과하지 않도록 제한
MaxRetryDelay *time.Duration
// MaxBytes HTTP 응답 본문의 최대 허용 크기입니다. (단위: 바이트)
//
// 설정 규칙:
// - nil: 기본값으로 보정
// - NoLimit(-1): 크기 제한을 적용하지 않음 (주의: 메모리 고갈 위험 있음)
// - 0 이하: 유효하지 않은 값으로 간주하여 기본값으로 보정
// - 양수: 지정된 크기만큼 HTTP 응답 본문의 허용 크기를 제한
MaxBytes *int64
// DisableStatusCodeValidation HTTP 응답 상태 코드 검증 사용 여부를 제어합니다.
//
// 설정 값:
// - false (기본값): 검증 활성화 (200 OK 또는 AllowedStatusCodes만 허용)
// - true: 검증 비활성화 (모든 상태 코드 허용, 커스텀 에러 처리가 필요한 경우)
DisableStatusCodeValidation bool
// AllowedStatusCodes 허용할 HTTP 응답 상태 코드 목록입니다.
//
// 설정 값:
// - nil/빈 슬라이스: 200 OK만 허용
// - 값 지정: 지정된 코드들만 허용
AllowedStatusCodes []int
// AllowedMimeTypes 허용할 HTTP 응답의 MIME 타입 목록입니다.
//
// 설정 값:
// - nil/빈 슬라이스: MIME 타입 검증 생략
// - 값 지정: "text/html" 같이 파라미터를 제외한 순수 MIME 타입만 허용 (대소문자 구분 안 함)
AllowedMimeTypes []string
// DisableLogging HTTP 요청/응답 로깅 사용 여부를 제어합니다.
//
// 설정 값:
// - false (기본값): 로깅 활성화 (URL, 상태 코드, 실행 시간 등을 기록)
// - true: 로깅 비활성화 (성능 향상 또는 민감한 정보 보호가 필요한 경우)
DisableLogging bool
// DisableTransportCaching Transport 캐싱 사용 여부를 제어합니다.
//
// 설정 값:
// - false (기본값/권장): 캐시 활성화 (성능 최적화)
// - true: 캐시 비활성화 (테스트 또는 완전한 격리가 필요한 경우)
DisableTransportCaching bool
}
Config Fetcher 체인을 구성하기 위한 모든 설정 옵션을 정의하는 구조체입니다.
type Fetcher ¶
Fetcher HTTP 요청을 수행하는 핵심 인터페이스입니다.
이 인터페이스는 다양한 HTTP 클라이언트 구현체들이 공통으로 따르는 규약을 정의합니다. 재시도, 로깅, User-Agent 설정 등의 기능을 데코레이터 패턴으로 조합할 수 있도록 설계되었습니다.
구현 시 주의사항:
- 반환된 응답 객체의 Body는 반드시 호출자가 닫아야 합니다.
- 에러가 발생해도 응답 객체가 nil이 아닐 수 있습니다 (예: 상태 코드 에러, 리다이렉트 에러).
- Context 취소 시 즉시 요청을 중단하고 적절한 에러를 반환해야 합니다.
func New ¶
New 주요 설정값(재시도 횟수, 지연 시간, 본문 크기 제한)만으로 빠르고 간편하게 Fetcher를 생성합니다.
이 함수는 내부적으로 Config를 생성하고 applyDefaults()를 통해 안전한 기본값을 적용한 후, NewFromConfig()를 호출하여 최적화된 Fetcher 체인을 구성합니다.
복잡한 설정(타임아웃, 프록시, 유효성 검사 등)이 필요한 경우에는 NewFromConfig 함수를 직접 사용하는 것을 권장합니다.
매개변수:
- maxRetries: 최대 재시도 횟수 (권장: 0~10회, 범위 초과 시 내부 정책에 따라 자동 보정)
- minRetryDelay: 최소 재시도 대기 시간 (최소: 1초, 서버 부하 방지를 위해 1초 미만은 1초로 자동 보정)
- maxBytes: 응답 본문의 최대 허용 크기 (0: 기본값 사용, -1: 제한 없음, 양수: 지정된 바이트로 제한)
- opts: HTTPFetcher 추가 설정 옵션 (예: WithTimeout, WithProxy)
반환값:
- Fetcher: 구성된 Fetcher 체인 인터페이스
func NewFromConfig ¶
NewFromConfig Config 기반 옵션과 추가 옵션을 기반으로 최적화된 Fetcher 실행 체인을 생성합니다.
Fetcher 체인은 책임 연쇄 패턴(Chain of Responsibility)을 따르며, 다음과 같은 순서로 미들웨어가 구성됩니다 (바깥쪽 -> 안쪽):
- [관찰] LoggingFetcher (최외곽): 모든 시도와 지연을 포함한 전체 요청 생애주기를 기록합니다.
- [보조] UserAgentFetcher (보조): 각 요청에 매번 새로운 User-Agent를 부여합니다.
- [제어] RetryFetcher (핵심): 실패 시 지수 백오프 전략에 따라 재시도를 총괄 제어합니다.
- [검증] MimeTypeFetcher (검증): 서버가 반환한 Content-Type의 유효성을 검사합니다.
- [검증] StatusCodeFetcher (검증): HTTP 응답 상태 코드의 유효성을 검사합니다.
- [제한] MaxBytesFetcher (보호): 응답 본문의 크기를 실시간으로 감시하여 메모리 고갈을 방지합니다.
- [전송] HTTPFetcher (최내곽): 최하단에서 실제 네트워크 I/O 및 패킷 전송을 담당합니다.
설계 의도:
- LoggingFetcher는 재시도를 포함한 전체 흐름을 기록하기 위해 가장 바깥에 위치합니다.
- RetryFetcher는 하위 검증 로직(상태 코드, MimeType) 실패 시에도 재시도를 수행해야 하므로 검증 미들웨어보다 바깥에 위치합니다.
- 검증 로직(StatusCode, MimeType)은 각 시도(Attempt)마다 수행되어야 하므로 RetryFetcher 안쪽에 위치합니다.
매개변수:
- cfg: Fetcher 체인 구성을 위한 상세 설정값
- opts: HTTPFetcher 내부 동작을 제어하기 위한 추가 옵션
반환값:
- Fetcher: 구성된 Fetcher 체인 인터페이스
func NewMaxBytesFetcher ¶
NewMaxBytesFetcher 새로운 MaxBytesFetcher 인스턴스를 생성합니다.
type HTTPFetcher ¶
type HTTPFetcher struct {
// contains filtered or unexported fields
}
HTTPFetcher 기본 HTTP 클라이언트 미들웨어입니다.
주요 기능:
- 타임아웃 관리: 전체 요청 타임아웃, 헤더 응답 타임아웃, TLS 핸드셰이크 타임아웃
- 연결 풀링: 유휴 연결 재사용, 호스트별 연결 수 제한
- 프록시 지원: HTTP/HTTPS 프록시 서버 설정
- Transport 캐싱: 동일한 설정의 요청들이 Transport를 공유하여 성능 최적화
- User-Agent 관리: 기본 User-Agent 설정 및 요청별 커스터마이징
func NewHTTPFetcher ¶
func NewHTTPFetcher(opts ...Option) *HTTPFetcher
NewHTTPFetcher 새로운 HTTPFetcher 인스턴스를 생성합니다.
이 함수는 Functional Options 패턴을 사용하여 유연한 설정을 지원합니다. 기본값으로 초기화된 후 제공된 옵션들을 순차적으로 적용합니다.
매개변수:
- opts: 설정 옵션들 (가변 인자)
반환값:
- *HTTPFetcher: 설정이 적용된 HTTPFetcher 인스턴스
주의사항:
- 초기화 중 에러 발생 시 initErr 필드에 저장되며, Do 호출 시 반환됨!
- Transport 캐싱은 성능 최적화를 위해 기본적으로 활성화됨!
func (*HTTPFetcher) Close ¶
func (h *HTTPFetcher) Close() error
Close HTTPFetcher가 사용 중인 네트워크 리소스를 정리합니다.
이 메서드는 HTTPFetcher가 더 이상 필요하지 않을 때 호출하여 메모리 누수를 방지합니다. 하지만 모든 리소스를 무조건 정리하는 것이 아니라, 안전하게 정리할 수 있는 것만 선별적으로 처리합니다.
왜 선별적으로 정리할까요?
Transport는 여러 HTTPFetcher가 공유할 수 있는 리소스입니다. 만약 다른 곳에서 사용 중인 Transport를 닫아버리면, 그곳의 네트워크 연결이 끊어지는 문제가 발생합니다. 따라서 이 메서드는 "내가 독점적으로 사용하는 리소스"만 정리합니다.
동작 방식:
전역 Transport (defaultTransport) - 정리하지 않음 - 이유: 애플리케이션 전체에서 공유하는 싱글톤 리소스이므로, 닫으면 다른 모든 클라이언트의 연결이 끊어집니다.
공유 Transport (캐시에 등록된 Transport) - 정리하지 않음 - 이유: 동일한 설정을 가진 다른 HTTPFetcher들이 함께 사용 중일 수 있으므로, 닫으면 다른 인스턴스에 영향을 줍니다.
격리된 Transport (DisableTransportCaching 옵션으로 생성된 전용 Transport) - 정리함 (CloseIdleConnections 호출) - 이유: 이 HTTPFetcher만 사용하는 독립적인 리소스이므로, 안전하게 유휴 연결을 닫을 수 있습니다.
반환값:
- error: 항상 nil (인터페이스 호환성을 위해 유지)
주의사항:
- Close 호출 후 Do 메서드를 다시 호출하는 것은 권장하지 않습니다.
- 공유 리소스는 Go의 가비지 컬렉터(GC)가 자동으로 관리하므로, 수동으로 정리할 필요가 없습니다.
func (*HTTPFetcher) Do ¶
Do HTTP 요청을 수행합니다.
이 메서드는 표준 http.Client.Do와 유사하지만, 다음과 같은 추가 기능을 제공합니다:
- 초기화 에러 확인: NewHTTPFetcher에서 발생한 에러가 있으면 즉시 반환
- 요청 객체 복제: 원본 요청 객체를 보호하기 위해 복제본 사용
- 기본 헤더 자동 추가: Accept, Accept-Language, User-Agent
매개변수:
- req: 처리할 HTTP 요청
반환값:
- HTTP 응답 객체 (성공 시)
- 에러 (요청 처리 중 발생한 에러)
주의사항:
- 원본 요청 객체는 수정되지 않음 (복제본 사용)
- 요청 객체에 이미 헤더가 설정되어 있으면 덮어쓰지 않음
- 반환된 응답 객체의 Body는 호출자가 반드시 닫아야 함
type HTTPStatusError ¶
type HTTPStatusError struct {
// StatusCode 서버가 반환한 HTTP 상태 코드입니다.
// 예: 200 (성공), 404 (Not Found), 500 (Internal Server Error)
StatusCode int
// Status HTTP 상태 코드에 대응하는 텍스트 설명입니다.
// 예: "200 OK", "404 Not Found", "500 Internal Server Error"
Status string
// URL 요청을 보낸 대상 URL입니다.
// 민감한 정보(비밀번호, 토큰 등)는 자동으로 마스킹됩니다.
URL string
// Header 서버가 반환한 HTTP 응답 헤더입니다.
// 민감한 헤더(Authorization, Cookie 등)는 자동으로 마스킹됩니다.
// 디버깅 및 문제 분석 시 유용한 정보를 제공합니다.
Header http.Header
// BodySnippet 응답 본문의 일부(최대 4KB)입니다.
// 전체 본문을 저장하지 않고 앞부분만 캡처하여 메모리 효율성을 유지합니다.
// 에러 원인 파악 및 디버깅 용도로 사용됩니다.
BodySnippet string
// Cause 이 HTTP 에러의 근본 원인이 되는 내부 도메인 에러입니다.
// 주로 apperrors.AppError 타입의 에러가 저장되며,
// Unwrap() 메서드를 통해 표준 에러 체이닝 패턴을 지원합니다.
Cause error
}
HTTPStatusError HTTP 요청 실패 시 상태 코드와 응답 정보를 포함하는 구조화된 에러입니다.
개요 ¶
이 에러 타입은 HTTP 요청이 실패했을 때 단순한 에러 메시지 대신 풍부한 컨텍스트 정보를 제공합니다. 상태 코드, URL, 응답 헤더, 응답 본문 일부 등을 구조화된 필드로 제공하여, 호출자가 에러 상황을 정확히 파악하고 적절한 대응(재시도, 로깅, 알림 등)을 할 수 있도록 돕습니다.
사용 예시 ¶
resp, err := fetcher.Do(req)
if err != nil {
var httpErr *HTTPStatusError
if errors.As(err, &httpErr) {
// HTTP 상태 코드별 처리
switch httpErr.StatusCode {
case 404:
log.Warn("리소스를 찾을 수 없음", "url", httpErr.URL)
case 500:
log.Error("서버 에러 발생", "body", httpErr.BodySnippet)
}
}
}
에러 체이닝 지원 ¶
Cause 필드에 apperrors.AppError를 포함하여 에러 타입 분류와 체이닝을 지원합니다. 표준 Unwrap() 메서드를 통해 errors.Is 및 errors.As와 같은 Go 표준 에러 체이닝 기능을 활용할 수 있습니다.
func (*HTTPStatusError) Error ¶
func (e *HTTPStatusError) Error() string
Error 표준 error 인터페이스를 구현합니다.
HTTP 상태 코드와 함께 URL, 응답 본문 일부, 원인 에러 등의 상세 정보를 포함한 사람이 읽기 쉬운 형태의 에러 메시지를 반환합니다.
반환 형식:
"HTTP {상태코드} ({상태텍스트}) URL: {URL}, Body: {본문일부}: {원인에러}"
예시:
"HTTP 404 (Not Found) URL: https://example.com/api/users/123, Body: {\"error\":\"user not found\"}: 사용자를 찾을 수 없습니다"
func (*HTTPStatusError) Unwrap ¶
func (e *HTTPStatusError) Unwrap() error
Unwrap 표준 errors 패키지의 Unwrap 인터페이스를 구현합니다.
이 메서드는 래핑된 원인 에러(Cause)를 반환하여, errors.Is() 및 errors.As()와 같은 Go 표준 에러 체이닝 기능을 사용할 수 있게 합니다.
반환값:
- Cause 필드에 저장된 원인 에러 (nil일 수 있음)
type LoggingFetcher ¶
type LoggingFetcher struct {
// contains filtered or unexported fields
}
LoggingFetcher HTTP 요청의 상세 정보를 로그로 남기는 미들웨어입니다.
로깅되는 정보:
- 요청 메서드 (GET, POST 등)
- 요청 URL (민감 정보 마스킹 처리됨)
- 응답 상태 코드 (200, 404, 500 등)
- 요청 처리 소요 시간
- 에러 메시지 (에러 발생 시)
func NewLoggingFetcher ¶
func NewLoggingFetcher(delegate Fetcher) *LoggingFetcher
NewLoggingFetcher 새로운 LoggingFetcher 인스턴스를 생성합니다.
func (*LoggingFetcher) Close ¶
func (f *LoggingFetcher) Close() error
type MaxBytesFetcher ¶
type MaxBytesFetcher struct {
// contains filtered or unexported fields
}
MaxBytesFetcher HTTP 응답 본문의 크기를 제한하는 미들웨어입니다.
주요 기능:
- Content-Length 헤더 기반 조기 차단 (네트워크 대역폭 절약)
- 실제 읽기 시점의 바이트 수 제한 (악의적인 Content-Length 조작 방어)
func (*MaxBytesFetcher) Close ¶
func (f *MaxBytesFetcher) Close() error
type MimeTypeFetcher ¶
type MimeTypeFetcher struct {
// contains filtered or unexported fields
}
MimeTypeFetcher HTTP 응답의 MIME 타입을 검증하는 미들웨어입니다.
주요 목적:
- HTML/텍스트 수집 작업 중 의도치 않은 대용량 바이너리 파일(이미지, 동영상 등) 다운로드 방지
- 허용된 MIME 타입만 처리하여 메모리 및 네트워크 리소스 보호
- 잘못된 MIME 타입을 조기에 감지하여 불필요한 처리 방지
func (*MimeTypeFetcher) Close ¶
func (f *MimeTypeFetcher) Close() error
type Option ¶
type Option func(*HTTPFetcher)
Option HTTPFetcher의 설정을 변경하기 위한 함수 타입입니다.
Functional Options 패턴을 사용하여 선택적 매개변수를 유연하게 설정할 수 있습니다. 각 Option 함수는 HTTPFetcher의 특정 필드를 수정합니다.
func WithCookieJar ¶
WithCookieJar HTTP 클라이언트에 쿠키 관리자(CookieJar)를 설정합니다.
CookieJar를 설정하면 HTTP 응답의 Set-Cookie 헤더를 자동으로 저장하고, 동일한 도메인에 대한 후속 요청에 쿠키를 자동으로 포함합니다.
매개변수:
- jar: http.CookieJar 구현체 (예: cookiejar.New(nil))
사용 예시:
jar, _ := cookiejar.New(nil) fetcher := NewHTTPFetcher(WithCookieJar(jar))
func WithDisableTransportCaching ¶
WithDisableTransportCaching Transport 캐싱 사용 여부를 설정합니다.
기본적으로 동일한 설정의 요청들은 Transport를 공유하여 성능을 최적화합니다. 캐싱을 비활성화하면 매번 새로운 Transport를 생성하여 완전히 격리된 환경을 제공합니다.
매개변수:
- disable: Transport 캐싱 비활성화 여부 · false (기본값): 캐시 사용 (성능 최적화) · true: 캐시 비활성화 (격리된 환경, 테스트에 유용)
주의사항:
- 캐시 비활성화 시 성능 저하 및 메모리 사용량 증가 가능
func WithIdleConnTimeout ¶
WithIdleConnTimeout 유휴 연결 타임아웃을 설정합니다.
사용되지 않는 연결을 유지할 최대 시간입니다. 이 시간이 지나면 연결이 자동으로 닫히고 풀에서 제거됩니다.
매개변수:
- timeout: 유휴 연결 타임아웃 · 0: 제한 없음 (연결이 무기한 유지) · 양수: 지정된 시간 후 연결 종료 · 음수: 기본값으로 보정
func WithMaxConnsPerHost ¶
WithMaxConnsPerHost 호스트당 최대 연결 개수를 설정합니다.
매개변수:
- max: 호스트당 최대 연결 개수 · 0: 무제한 · 양수: 지정된 개수로 제한 · 음수: 기본값으로 보정
func WithMaxIdleConns ¶
WithMaxIdleConns 전체 유휴 연결의 최대 개수를 설정합니다.
매개변수:
- max: 전체 유휴 연결의 최대 개수 · 0: 무제한 · 양수: 지정된 개수로 제한 · 음수: 기본값으로 보정
func WithMaxIdleConnsPerHost ¶
WithMaxIdleConnsPerHost 호스트당 유휴 연결의 최대 개수를 설정합니다.
매개변수:
- max: 호스트당 유휴 연결의 최대 개수 · 0: net/http가 기본값 2로 해석 · 양수: 지정된 개수로 제한 · 음수: 기본값으로 보정
func WithMaxRedirects ¶
WithMaxRedirects HTTP 클라이언트의 최대 리다이렉트 횟수를 설정합니다.
기본적으로 Go HTTP 클라이언트는 최대 10번까지 리다이렉트를 따라갑니다. 이 옵션으로 제한을 변경할 수 있으며, 리다이렉트 시 Referer 헤더를 자동으로 설정합니다.
매개변수:
- max: 최대 리다이렉트 횟수 · 0: 리다이렉트 허용 안 함 · 양수: 지정된 횟수만큼 리다이렉트 허용 · 음수: 기본값으로 보정
func WithProxy ¶
WithProxy 프록시 URL을 설정합니다.
모든 HTTP/HTTPS 요청이 지정된 프록시 서버를 통해 전송됩니다.
매개변수:
- proxyURL: 프록시 URL · URL: 지정된 프록시 서버 사용 (예: "http://proxy:8080") · NoProxy(또는 "DIRECT") 또는 빈 문자열(""): 프록시 비활성화 (환경 변수 무시, 직접 연결)
func WithResponseHeaderTimeout ¶
WithResponseHeaderTimeout HTTP 응답 헤더 대기 타임아웃을 설정합니다.
이 타임아웃은 요청을 보낸 후 응답 헤더를 받을 때까지의 시간을 제한합니다. 응답 본문 읽기 시간은 포함되지 않으므로, 전체 타임아웃(WithTimeout)과 함께 사용하세요.
매개변수:
- timeout: 응답 헤더 대기 타임아웃 · 0: 타임아웃 없음 (무한 대기) · 양수: 지정된 시간으로 제한 · 음수: 0으로 보정
func WithTLSHandshakeTimeout ¶
WithTLSHandshakeTimeout TLS 핸드셰이크 타임아웃을 설정합니다.
HTTPS 연결 시 SSL/TLS 협상에 허용되는 최대 시간입니다. 네트워크가 느리거나 서버 부하가 높을 때 타임아웃이 발생할 수 있습니다.
매개변수:
- timeout: TLS 핸드셰이크 타임아웃 · 0: 타임아웃 없음 (무한 대기) · 양수: 지정된 시간으로 제한 · 음수: 기본값으로 보정
func WithTimeout ¶
WithTimeout HTTP 요청 전체에 대한 타임아웃을 설정합니다.
이 타임아웃은 요청 시작부터 응답 완료까지의 전체 시간을 제한합니다. DNS 조회, 연결, TLS 핸드셰이크, 응답 헤더, 응답 본문 읽기 등 모든 단계를 포함합니다.
매개변수:
- timeout: 요청 전체에 대한 타임아웃 (예: 30*time.Second) · 0: 타임아웃 없음 (무한 대기) · 양수: 지정된 시간으로 제한 · 음수: 기본값으로 보정
func WithTransport ¶
func WithTransport(transport http.RoundTripper) Option
WithTransport HTTP 클라이언트의 Transport를 직접 설정합니다.
이 옵션은 고급 사용자를 위한 것으로, 표준 옵션으로 제공되지 않는 특수한 Transport 설정이 필요할 때 사용합니다. 예를 들어, 커스텀 Dialer, 특수한 TLS 설정, 또는 테스트용 모의(Mock) Transport를 주입할 수 있습니다.
⚠️ 중요: 커넥션 풀링 성능 저하 주의
WithTransport와 다른 Transport 설정 옵션(WithProxy, WithMaxIdleConns, WithTLSHandshakeTimeout 등)을 함께 사용하면 매번 새로운 커넥션 풀이 생성되어 성능이 크게 저하됩니다.
권장 사용법:
- Transport 설정이 필요하면 WithTransport 없이 옵션만 사용 (내부 캐싱 활용)
- WithTransport 사용 시 모든 설정을 완료한 Transport를 주입
참고: WithTimeout은 http.Client 설정이므로 이 제약에 해당하지 않습니다.
매개변수:
- transport: 사용할 http.RoundTripper 구현체 (일반적으로 *http.Transport 또는 테스트용 Mock)
주의사항:
- *http.Transport가 아닌 RoundTripper를 제공하면서 Transport 관련 옵션을 함께 사용하면, Do() 호출 시 ErrUnsupportedTransport 에러가 반환됩니다.
- 옵션 없이 사용하면 제공된 RoundTripper를 그대로 사용하며 정상 동작합니다.
- Transport 캐싱이 비활성화되므로 성능 최적화 효과가 감소할 수 있습니다.
- 일반적인 경우에는 표준 옵션(WithProxy, WithMaxIdleConns 등)을 사용하는 것을 권장합니다.
타입별 동작 방식:
*http.Transport 타입 (일반적인 경우): - 원본을 복제한 후, 사용자가 설정한 Transport 관련 옵션들을 선택적으로 덮어씁니다. - WithProxy, WithMaxIdleConns 등의 옵션이 정상적으로 적용됩니다.
다른 RoundTripper 타입 (Mock 등): a) Transport 관련 옵션을 사용하지 않은 경우: 제공된 객체를 그대로 사용하며 정상 동작합니다. 이 경우 needsCustomTransport()가 false를 반환하여 setupTransport()가 조기 종료됩니다.
b) Transport 관련 옵션(WithProxy, WithMaxIdleConns 등)을 함께 사용한 경우: NewHTTPFetcher()는 성공하지만, Do() 호출 시 ErrUnsupportedTransport 에러를 반환합니다. 이는 *http.Transport가 아닌 타입은 내부 설정(프록시, 타임아웃 등)을 변경할 수 없기 때문입니다. setupTransport()에서 타입 검사 후 에러를 initErr에 저장하며, Do() 실행 시 이 에러가 반환됩니다.
캐싱 비활성화 이유:
- 외부에서 주입된 Transport는 소유권과 생명주기를 fetcher가 제어할 수 없습니다.
- 다른 곳에서도 동일한 Transport를 사용 중일 수 있어, 캐시 관리 로직이 리소스를 정리하면 예상치 못한 부작용이 발생할 수 있습니다.
- 따라서 격리 모드로 동작하여 사용자가 직접 Transport의 생명주기를 관리하도록 합니다.
func WithUserAgent ¶
WithUserAgent 기본 User-Agent를 설정합니다.
이 옵션으로 설정한 User-Agent는 요청 헤더에 User-Agent가 없을 때만 자동으로 추가됩니다. 요청 헤더에 이미 User-Agent가 설정되어 있으면 그 값이 우선적으로 사용됩니다.
매개변수:
- ua: User-Agent 문자열 (예: "MyBot/1.0", "Mozilla/5.0 ...")
type RetryFetcher ¶
type RetryFetcher struct {
// contains filtered or unexported fields
}
RetryFetcher HTTP 요청 실패 시 자동으로 재시도를 수행하는 미들웨어입니다.
주요 특징:
- 지수 백오프(Exponential Backoff): 재시도 간격을 지수적으로 증가시켜 서버 부하를 분산
- Jitter: 무작위 지연을 추가하여 동시 다발적인 재시도로 인한 "Thundering Herd" 문제 방지
- Retry-After 헤더 지원: 서버가 명시한 재시도 시간을 우선적으로 준수
- 컨텍스트 취소 감지: 사용자 요청 취소 시 즉시 재시도 중단
func NewRetryFetcher ¶
func NewRetryFetcher(delegate Fetcher, maxRetries int, minRetryDelay time.Duration, maxRetryDelay time.Duration) *RetryFetcher
NewRetryFetcher 새로운 RetryFetcher 인스턴스를 생성합니다.
func (*RetryFetcher) Close ¶
func (f *RetryFetcher) Close() error
func (*RetryFetcher) Do ¶
Do HTTP 요청을 수행하며, 실패 시 설정된 정책에 따라 자동으로 재시도합니다.
재시도 전략:
- 지수 백오프(Exponential Backoff): 재시도 간격을 지수적으로 증가 (예: 1초 → 2초 → 4초 → 8초 → ...) - 공식: delay = minRetryDelay * 2^(retry-1) - 재시도 대기 시간의 최대값(maxRetryDelay)을 초과하지 않도록 제한
- Full Jitter: 계산된 재시도 대기 시간 범위 내에서 무작위 값 선택 (0 ~ delay) - Thundering Herd 문제 방지: 여러 클라이언트가 동시에 재시도하는 것을 분산
- Retry-After 헤더 우선 처리: - 서버가 Retry-After 헤더를 제공하면 해당 시간을 우선 사용 - 단, 재시도 대기 시간의 최대값(maxRetryDelay)을 초과하면 재시도하지 않고 에러 반환
- 멱등성 검증: - GET, HEAD, PUT, DELETE, OPTIONS, TRACE: 재시도 허용 - POST, PATCH: 재시도 제외 (데이터 중복 생성/수정 위험)
- 컨텍스트 취소 감지: - 대기 중 컨텍스트가 취소되면 즉시 재시도 중단
재시도 대상:
- 네트워크 오류 (타임아웃, 연결 실패 등)
- 5xx 서버 에러 (단, 501/505/511 제외)
- 429 Too Many Requests
- 408 Request Timeout
재시도 제외:
- 컨텍스트 취소 (context.Canceled)
- 4xx 클라이언트 에러 (400, 401, 403, 404 등)
- 비즈니스 로직 에러 (apperrors.ExecutionFailed, InvalidInput, Forbidden, NotFound)
매개변수:
- req: 처리할 HTTP 요청 객체
반환값:
- HTTP 응답 객체 (성공 시)
- 에러 (최대 재시도 횟수 초과 또는 재시도 불가능한 에러 발생 시)
주의사항:
- 요청 객체의 Body가 있는 경우 반드시 GetBody 필드를 설정해야 합니다.
- 비멱등 메서드(POST, PATCH)는 자동으로 재시도가 제외됩니다.
- 반환된 응답 객체의 Body는 호출자가 반드시 닫아야 합니다.
type StatusCodeFetcher ¶
type StatusCodeFetcher struct {
// contains filtered or unexported fields
}
StatusCodeFetcher HTTP 응답의 상태 코드를 검증하는 미들웨어입니다.
주요 목적:
- 허용된 HTTP 응답 상태 코드만 성공으로 처리
- 허용되지 않은 응답 상태 코드 조기 감지 및 에러 반환
- 실패한 응답의 리소스를 안전하게 정리하여 커넥션 재사용 보장
func NewStatusCodeFetcher ¶
func NewStatusCodeFetcher(delegate Fetcher) *StatusCodeFetcher
NewStatusCodeFetcher 200 OK만 허용하는 StatusCodeFetcher 인스턴스를 생성합니다.
func NewStatusCodeFetcherWithOptions ¶
func NewStatusCodeFetcherWithOptions(delegate Fetcher, allowedStatusCodes ...int) *StatusCodeFetcher
NewStatusCodeFetcherWithOptions 특정 HTTP 응답 상태 코드들을 허용하는 StatusCodeFetcher 인스턴스를 생성합니다.
func (*StatusCodeFetcher) Close ¶
func (f *StatusCodeFetcher) Close() error
func (*StatusCodeFetcher) Do ¶
Do HTTP 요청을 수행하고 응답 상태 코드를 검증합니다.
매개변수:
- req: 처리할 HTTP 요청
반환값:
- HTTP 응답 객체 (성공 시)
- 에러 (요청 처리 중 발생한 에러)
주의사항:
- 응답 상태 코드 검증 실패 시 nil Response를 반환하므로, 호출자는 에러 체크 후 Response를 사용해야 합니다.
- 에러 발생 시(Delegate 에러 또는 응답 상태 코드 검증 실패) 응답 객체의 Body는 이 함수 내부에서 자동으로 정리되므로, 호출자가 별도로 닫을 필요가 없습니다.
- 성공 시에는 호출자가 반드시 응답 객체의 Body를 닫아야 합니다.
type UserAgentFetcher ¶
type UserAgentFetcher struct {
// contains filtered or unexported fields
}
UserAgentFetcher HTTP 요청에 User-Agent를 주입하는 미들웨어입니다.
주요 기능:
- 요청에 User-Agent가 없을 경우에만 랜덤으로 선택하여 주입합니다.
- 요청에 User-Agent가 있을 경우에는 수정하지 않고 그대로 전달합니다.
- User-Agent를 랜덤으로 선택하여 웹 스크래핑 시 차단을 회피할 수 있습니다.
func NewUserAgentFetcher ¶
func NewUserAgentFetcher(delegate Fetcher, userAgents []string) *UserAgentFetcher
NewUserAgentFetcher 새로운 UserAgentFetcher 인스턴스를 생성합니다.
func (*UserAgentFetcher) Close ¶
func (f *UserAgentFetcher) Close() error
func (*UserAgentFetcher) Do ¶
Do HTTP 요청을 수행하며, 필요한 경우 User-Agent를 랜덤으로 선택하여 주입합니다.
매개변수:
- req: 처리할 HTTP 요청
반환값:
- HTTP 응답 객체 (성공 시)
- 에러 (요청 처리 중 발생한 에러)
주의사항:
- 이 메서드는 원본 요청 객체를 수정하지 않습니다.
- User-Agent 주입이 필요한 경우 req.Clone()을 사용하여 복제본을 생성합니다.
- 재시도 시에도 동일한 User-Agent를 유지하려면 이 미들웨어를 RetryFetcher보다 상위에 배치해야 합니다.