콘텐츠로 이동

Client와 요청의 생애

목차 | 이전: Streaming | 다음: Redirect·Retry·Cookie

이 장을 읽고 나면

HTTP 호출 자원을 재사용하고 닫는 시점, 요청을 끝내는 방법, timeout과 옵션의 적용 범위를 판단할 수 있다. 생성 코드는 각 언어의 HttpClient tutorial에서 가져왔다.

client는 base URL과 전송 옵션을 가진 재사용 단위다. builder는 client를 만들고, client가 만든 request builder는 HTTP method·path·body를 모은다. 종결자(terminator)는 모은 요청을 제출하고 응답 형태를 결정하는 마지막 호출이다.

1. Builder에서 응답까지 흐른다

↗ 크게 보기

client는 같은 대상 서비스에 보내는 요청의 connection pool과 기본값을 유지한다. request builder는 요청 하나에만 속하며, 종결자를 호출하면 그 요청을 제출한다.

2. Client 하나를 만들고 재사용한다

서비스마다 client 하나를 만들고 여러 요청에 재사용한다. 요청마다 build하면 keep-alive와 connection pool을 다시 만들게 된다. 사용이 끝난 client는 해당 언어의 resource 관리 방식으로 닫는다.

ZLinkHttpClient client =
        ZLinkHttpClient.create("http://127.0.0.1:5280")
                .timeout(Duration.ofSeconds(3))
                .build();

예제는 base URL과 3초 timeout으로 client 하나를 만들고 프로그램이 끝날 때 닫는 수명 범위를 보여 준다.

Spot 또는 channel handler는 static factory로 client를 새로 만들지 않고 DI로 주입된 client를 사용한다. 이 경계가 handler 사이의 connection pool 재사용과 framework 실행 문맥을 보존한다.

3. 응답 형태에 맞는 종결자를 고른다

종결자는 request builder를 실제 HTTP 요청으로 제출한다. typed 응답은 status와 header, JSON으로 읽은 body를 함께 담고, raw 응답은 status와 header, JSON으로 읽기 전 body를 담는다. 같은 응답 형태라도 언어마다 표기만 다르며, 표의 이름은 호출 위치의 실행 모델과 별개로 응답을 받는 역할을 나타낸다.

응답 형태 C++ C#/.NET Java Kotlin Node/TypeScript
typed 응답 HttpResponse<T> async<T>() Async<T>(ct?) submit(Class<T>) await(type) / await<T>() (suspend) submit<T>()
raw 응답 async_raw() AsyncRaw(ct?) submitRaw() awaitRaw() (suspend) submitRaw()
decoded body T만 fetch<T>() Fetch<T>(ct?) fetch(Class<T>) fetch<T>() (suspend) fetch<T>()
streaming download download(sink) DownloadAsync(sink, ct?) download(Consumer<byte[]>) awaitDownload(sink) download(sink)
callback 완료 async<T>(callback) Async<T>(callback) submit(Class<T>, callback) (suspend로 대체) submit<T>(callback)
gate 반납 (DI server builder 전용) yield<T>() Yield<T>(ct?) yield(Class<T>) yield<T>() (suspend) yield<T>()
blocking (CLI·client 시나리오 전용) submit_raw(), submit<T>() 두지 않는다 두지 않는다 두지 않는다 두지 않는다

4. Timeout의 두 경계를 구분한다

client timeout 기본값은 3000ms이며, 요청 builder의 timeout은 그 요청의 시도당 timeout만 바꾼다. retry를 켠 요청도 각 시도에 이 timeout을 적용한다. 전체 retry 시간을 하나로 제한하는 옵션은 없다.

5. 비동기 완료를 기다린다

비동기 종결자는 네트워크 대기 중 호출 thread나 event loop를 점유하지 않는다. 언어의 비동기 조합 방식으로 완료를 기다린다. blocking 종결자는 C++ CLI와 client 시나리오에만 있으며 framework runtime 실행 문맥에서는 사용할 수 없다.

6. Client 옵션을 한곳에서 정한다

옵션 기본값 의미
baseUrl 필수 모든 요청 path의 기준 URL
timeout 3000ms 시도당 timeout
defaultHeader 없음, 누적 모든 요청에 붙는 기본 header
basicAuth off Basic 인증
bearerToken off Bearer 인증
maxResponseBodySize 16 MiB 압축 해제 후에도 적용되는 body 상한
trustCertificateFile 시스템 root 신뢰 PEM 인증서를 추가
clientCertificateFile off mTLS client 인증서와 key
followRedirects off, 무인자 설정 시 5회 redirect 자동 추적 한도
retry off, 0회 추가 재시도 횟수
cookies off cookie jar 활성화
proxy off http:// proxy URL
proxyBasicAuth off proxy Basic 인증
compression off gzip·deflate 요청과 투명 해제

인증과 proxy 옵션은 인증·TLS·Proxy, streaming의 예외는 Streaming, redirect·retry의 세부 규칙은 Redirect·Retry·Cookie에서 다룬다.

7. One-shot은 한 번의 편의 경로다

client builder에서도 method를 바로 시작할 수 있다. 이 one-shot 경로는 제출할 때 client를 만들고 완료 후 닫으므로 connection pool을 재사용하지 않는다. one-shot request는 한 번 제출한 뒤 재제출할 수 없으며, 재제출하면 InvalidOperation으로 실패한다. 한 번뿐인 관리 작업에는 사용할 수 있지만, 반복 호출과 고부하 경로에는 재사용 client를 둔다.

8. 다음 장

redirect, retry, cookie jar의 자동 처리 규칙은 Redirect·Retry·Cookie에서 다룬다.