web-dev-qa-db-ja.com

Apache HttpClientタイムアウト

HttpClient の実行全体のタイムアウトを指定する方法はありますか?

私は次を試しました:

httpClient.getParams().setParameter("http.socket.timeout", timeout * 1000);
httpClient.getParams().setParameter("http.connection.timeout", timeout * 1000);
httpClient.getParams().setParameter("http.connection-manager.timeout", new Long(timeout * 1000));
httpClient.getParams().setParameter("http.protocol.head-body-timeout", timeout * 1000);

リモートホストが1バイト/秒であってもデータを送り返す場合を除いて、実際に正常に動作します。しかし、ホストが応答するかどうかに関係なく、最大10秒で接続を中断します。

50
Rosty Kerei

現在、その種の最大リクエスト期間を設定する方法はありません:基本的にあなたは言いたい私は気にしません特定のリクエストステージはタイムアウトになりますが、リクエスト全体が15秒より長く続くことはできません(たとえば)。

あなたの最善の策は、別のタイマーを実行し、それが期限切れになったら、HttpClientインスタンスが使用する接続マネージャーを取得し、接続をシャットダウンして、リンクを終了することです。それがあなたのために働くかどうか私に知らせてください。

31
Femi

Httpclientの新しいバージョン(例:http components 4.3- https://hc.Apache.org/httpcomponents-client-4.3.x/index.html ):

int CONNECTION_TIMEOUT_MS = timeoutSeconds * 1000; // Timeout in millis.
RequestConfig requestConfig = RequestConfig.custom()
    .setConnectionRequestTimeout(CONNECTION_TIMEOUT_MS)
    .setConnectTimeout(CONNECTION_TIMEOUT_MS)
    .setSocketTimeout(CONNECTION_TIMEOUT_MS)
    .build();

HttpPost httpPost = new HttpPost(URL);
httpPost.setConfig(requestConfig);
55
RealMan

Femiが提案したとおり、正常に動作します。ありがとう!

Timer timer = new Timer();
timer.schedule(new TimerTask() {
    public void run() {
        if(getMethod != null) {
            getMethod.abort();
        }
    }
}, timeout * 1000);
14
Rosty Kerei

他の答えを基に、私の解決策は、HttpRequestInterceptorを使用して、すべてのリクエストにアボート実行可能ファイルを追加することでした。また、TimerScheduledExecutorServiceに交換しました。

public class TimeoutInterceptor implements HttpRequestInterceptor {

private int requestTimeout = 1 * DateTimeConstants.MILLIS_PER_MINUTE;

private ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();

public TimeoutInterceptor() {  }

public TimeoutInterceptor(final int requestTimeout) {
    this.requestTimeout = requestTimeout;
}

@Override
public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException {
    if (request instanceof AbstractExecutionAwareRequest) {
        final AbstractExecutionAwareRequest abortableRequest = (AbstractExecutionAwareRequest) request;
        setAbort(abortableRequest);
    } else if (request instanceof HttpRequestWrapper) {
        HttpRequestWrapper wrapper = (HttpRequestWrapper) request;
        this.process(wrapper.getOriginal(), context);
    }

}

/**
 * @param abortableRequest
 */
private void setAbort(final AbstractExecutionAwareRequest abortableRequest) {
    final SoftReference<AbstractExecutionAwareRequest> requestRef = new SoftReference<AbstractExecutionAwareRequest>(abortableRequest);

    executorService.schedule(new Runnable() {

        @Override
        public void run() {
            AbstractExecutionAwareRequest actual = requestRef.get();
            if (actual != null && !actual.isAborted()) {
                actual.abort();
            }
        }
    }, requestTimeout, TimeUnit.MILLISECONDS);

}

public void setRequestTimeout(final int requestTimeout) {
    this.requestTimeout = requestTimeout;
}
}
3
mR_fr0g

タイマーは悪です。リクエストごとにスレッド/実行可能オブジェクトを作成するタイマーまたはエグゼキューターまたはその他のメカニズムを使用することは、非常に悪い考えです。賢明に考えて、それをしないでください。そうしないと、実際の環境が多かれ少なかれ、メモリの問題がすぐに発生します。私が提案するソリューションは、1つのウォッチドッグスレッドのみを必要とし、リソースの時間と神経を節約します。基本的には、3つのステップを実行します。 1.リクエストをキャッシュに入れる2.完了時にリクエストをキャッシュから削除する3.制限内で完了していないリクエストを中止する

キャッシュとウォッチドッグスレッドは次のようになります。

import org.Apache.http.client.methods.*;
import Java.util.*;
import Java.util.concurrent.*;
import Java.util.stream.*;

public class RequestCache {

private static final long expireInMillis = 300000;
private static final Map<HttpUriRequest, Long> cache = new ConcurrentHashMap<>();
private static final ScheduledExecutorService exe = Executors.newScheduledThreadPool(1);

static {
    // run clean up every N minutes
    exe.schedule(RequestCache::cleanup, 1, TimeUnit.MINUTES);
}

public static void put(HttpUriRequest request) {
    cache.put(request, System.currentTimeMillis());
}

public static void remove(HttpUriRequest request) {
    cache.remove(request);
}

private static void cleanup() {
    // find expired requests
    List<HttpUriRequest> expired = cache.entrySet().stream()
            .filter(e -> (System.currentTimeMillis() - e.getValue()) > expireInMillis)
            .map(Map.Entry::getKey)
            .collect(Collectors.toList());

    // abort requests
    expired.forEach(r -> {
        if (!r.isAborted()) {
            r.abort();
        }
        cache.remove(r);
      });
    }
  }

および次のSudoコードのキャッシュの使用方法

import org.Apache.http.client.methods.*;

public class RequestSample {

public void processRequest() {
    HttpUriRequest req = null;
    try {
        req = createRequest();

        RequestCache.put(req);

        execute(req);

    } finally {
        RequestCache.remove(req);
    }
  }
}
2
Valchkou

HttpClient 4.3バージョンでは、以下の例を使用できます。5秒間言います

int timeout = 5;
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://localhost:8080/service"); // GET Request
response = client.execute(request);
1
MAA