1. 개요

이 예제은 Apache HttpClient 4 로 타임아웃설정하는 방법을 보여줄 것 입니다.

더 깊이 파고들고 HttpClient로 할 수 있는 다른 멋진 것들을 배우고 싶다면 메인 HttpClient 예제로 넘어가십시오 .

2. HttpClient 4.3 이전에 타임아웃 설정하기

2.1. 원시 문자열 매개변수

버전 4.3이 나오기 전에 HttpClient 에는 많은 구성 매개변수가 있었고 이 모든 매개변수는 Map와 같은 일반적인 방식으로 설정할 수 있었습니다.

구성할 시간 초과 매개변수3개 있습니다 .

DefaultHttpClient httpClient = new DefaultHttpClient();

int timeout = 5; // seconds
HttpParams httpParams = httpClient.getParams();
httpParams.setParameter(
  CoreConnectionPNames.CONNECTION_TIMEOUT, timeout * 1000);
httpParams.setParameter(
  CoreConnectionPNames.SO_TIMEOUT, timeout * 1000);
httpParams.setParameter(
  ClientPNames.CONN_MANAGER_TIMEOUT, new Long(timeout * 1000));

2.2. API

이러한 매개변수 중 더 중요한 것, 즉 처음 두 개는 보다 유형이 안전한 API를 통해 설정할 수도 있습니다.

DefaultHttpClient httpClient = new DefaultHttpClient();

int timeout = 5; // seconds
HttpParams httpParams = httpClient.getParams();
HttpConnectionParams.setConnectionTimeout(
  httpParams, timeout * 1000); // http.connection.timeout
HttpConnectionParams.setSoTimeout(
  httpParams, timeout * 1000); // http.socket.timeout

세 번째 매개변수는 HttpConnectionParams 에 사용자 지정 설정자가 없으며 여전히 setParameter 메서드 를 통해 수동으로 설정해야 합니다 .

3. 새로운 기능을 사용하여 시간 초과 구성 4.3. 빌더

4.3에 도입된 유창한 빌더 API 는 높은 수준에서 시간 초과를 설정하는 올바른 방법을 제공 합니다 .

int timeout = 5;
RequestConfig config = RequestConfig.custom()
  .setConnectTimeout(timeout * 1000)
  .setConnectionRequestTimeout(timeout * 1000)
  .setSocketTimeout(timeout * 1000).build();
CloseableHttpClient client = 
  HttpClientBuilder.create().setDefaultRequestConfig(config).build();

이는 세 가지 제한 시간을 모두 형식이 안전하고 읽을 수 있는 방식으로 구성하는 데 권장되는 방법입니다.

4. 타임아웃 속성 설명

이제 이러한 다양한 유형의 시간 초과가 의미하는 바를 설명하겠습니다.

  • 연결 시간 제한 ( http.connection.timeout ) - 원격 호스트와의 연결을 설정하는 시간
  • 소켓 시간 초과 ( http.socket.timeout ) - 데이터를 기다리는 시간 - 연결을 수립 한 후, 두 데이터 패킷 간의 최대 비활성 시간
  • 연결 관리자 시간 초과 ( http.connection-manager.timeout ) - 시간은 연결 관리자 / 풀에서 연결을 위해 대기

처음 두 매개변수(연결 및 소켓 시간 초과)가 가장 중요합니다. 그러나 연결을 얻기 위한 시간 초과 설정은 부하가 높은 시나리오에서 확실히 중요하므로 세 번째 매개변수를 무시해서는 안 됩니다.

5. HttpClient 사용하기

구성한 후 이제 클라이언트를 사용하여 HTTP 요청을 수행할 수 있습니다.

HttpGet getMethod = new HttpGet("http://host:8080/path");
HttpResponse response = httpClient.execute(getMethod);
System.out.println(
  "HTTP Status of response: " + response.getStatusLine().getStatusCode());

이전에 정의한 클라이언트 를 사용하면 호스트에 대한 연결이 5초 후에 시간 초과됩니다. 또한 연결이 설정되었지만 데이터가 수신되지 않으면 타임아웃도 5초 추가 됩니다.

연결 시간 초과로 인해 org.apache.http.conn.ConnectTimeoutException 이 발생하고 소켓 시간 초과로 인해 java.net.SocketTimeoutException이 발생 합니다.

6. 하드 타임아웃

HTTP 연결을 설정하고 데이터를 수신하지 않을 때 타임아웃을 설정하는 것은 매우 유용하지만 때로는 전체 요청에 대해 하드 타임아웃 을 설정해야 합니다 .

예를 들어, 잠재적으로 큰 파일의 다운로드가 이 범주에 해당합니다. 이 경우 연결이 성공적으로 설정되고 데이터가 지속적으로 전달될 수 있지만 작업이 특정 시간 임계값을 초과하지 않도록 해야 합니다.

HttpClient 에는 요청에 대한 전체 시간 제한을 설정할 수 있는 구성이 없습니다. 그러나 요청에 대한 중단 기능을 제공 하므로 해당 메커니즘을 활용하여 간단한 시간 초과 메커니즘을 구현할 수 있습니다.

HttpGet getMethod = new HttpGet(
  "http://localhost:8080/httpclient-simple/api/bars/1");

int hardTimeout = 5; // seconds
TimerTask task = new TimerTask() {
    @Override
    public void run() {
        if (getMethod != null) {
            getMethod.abort();
        }
    }
};
new Timer(true).schedule(task, hardTimeout * 1000);

HttpResponse response = httpClient.execute(getMethod);
System.out.println(
  "HTTP Status of response: " + response.getStatusLine().getStatusCode());

우리는 사용하고있는 java.util.Timerjava.util.TimerTask 셋업하기 는 HTTP GET 요청을 중단 간단한 지연 작업 오초 하드 제한 시간 후입니다.

7. 타임아웃 및 DNS 라운드 로빈 – 주의해야 할 사항

일부 더 큰 도메인은 기본적으로 동일한 도메인이 여러 IP 주소에 매핑 되는 DNS 라운드 로빈 구성을 사용하는 것이 일반적입니다 . 이것은 HttpClient가 시간 초과되는 해당 도메인에 연결을 시도하는 방식 때문에 그러한 도메인에 대한 시간 초과에 대한 새로운 문제를 소개합니다.

  • HttpClient는 해당 도메인에 대한 IP 경로 List을 가져 옵니다.
  • 첫 번째 시도 - 시간 초과(우리가 구성한 시간 초과 포함)
  • 두 번째 시도 - 그것도 시간 초과됨
  • 등등 …

따라서 보시 다시피 전체 작업 시간이 초과되지 않을 것으로 예상됩니다 . 대신 – 가능한 모든 경로가 시간 초과되면 시간 초과됩니다. 게다가 이것은 클라이언트에 대해 완전히 투명하게 발생합니다(DEBUG 수준에서 로그를 구성하지 않은 경우).

다음은 이 문제를 실행하고 복제할 수 있는 간단한 예입니다.

int timeout = 3;
RequestConfig config = RequestConfig.custom().
  setConnectTimeout(timeout * 1000).
  setConnectionRequestTimeout(timeout * 1000).
  setSocketTimeout(timeout * 1000).build();
CloseableHttpClient client = HttpClientBuilder.create()
  .setDefaultRequestConfig(config).build();

HttpGet request = new HttpGet("http://www.google.com:81");
response = client.execute(request);

DEBUG 로그 수준의 재시도 논리를 확인할 수 있습니다.

DEBUG o.a.h.i.c.HttpClientConnectionOperator - Connecting to www.google.com/173.194.34.212:81
DEBUG o.a.h.i.c.HttpClientConnectionOperator - 
 Connect to www.google.com/173.194.34.212:81 timed out. Connection will be retried using another IP address

DEBUG o.a.h.i.c.HttpClientConnectionOperator - Connecting to www.google.com/173.194.34.208:81
DEBUG o.a.h.i.c.HttpClientConnectionOperator - 
 Connect to www.google.com/173.194.34.208:81 timed out. Connection will be retried using another IP address

DEBUG o.a.h.i.c.HttpClientConnectionOperator - Connecting to www.google.com/173.194.34.209:81
DEBUG o.a.h.i.c.HttpClientConnectionOperator - 
 Connect to www.google.com/173.194.34.209:81 timed out. Connection will be retried using another IP address
//...

8. 결론

이 사용방법(예제)에서는 HttpClient 에 사용할 수 있는 다양한 유형의 시간 초과를 구성하는 방법에 대해 설명했습니다 . 또한 진행 중인 HTTP 연결의 하드 타임아웃에 대한 간단한 메커니즘을 설명했습니다.

이러한 예제의 구현은 GitHub 프로젝트 에서 찾을 수 있습니다 .

HTTPClient footer