java - Apache Httpclient 中止请求导致错误

标签 java apache-httpclient-4.x

我有一个程序需要解决几个问题。对于每个问题,它可以并行尝试几种不同的算法。一旦一种算法解决了问题,我希望其他算法立即终止。有些算法是通过 HTTP 请求访问的:您将问题发送到服务器、阻止,然后服务器返回答案。如果另一个线程在服务器返回之前找到答案,我希望该线程取消 http 请求。

我最初使用Spring的RestTemplate,但我找不到这个功能。最终我偶然发现了 Apache 的 httpclient(我正在使用 org.apache.httpcomponents:httpclient:4.4.1)。 Apache Httpclient 表示它可以 abort requests ,所以我按如下方式使用它:

    // fields
        private final Lock lock;
        private final AtomicBoolean activeSolve;
        private HttpPost post;
        private final CloseableHttpClient httpClient = HttpClients.createDefault();


public String makePost() {
    post = new HttpPost("some url");
    final StringEntity stringEntity = new StringEntity("some json string", ContentType.APPLICATION_JSON);
    post.setEntity(stringEntity);
    try {
        lock.lock();
        activeSolve.set(true);
        lock.unlock();
        try (final CloseableHttpResponse httpResponse = httpClient.execute(post)) {
            final String response = EntityUtils.toString(httpResponse.getEntity());
            return response;
        }
    } catch (IOException e) {
        if (post.isAborted()) {
            log.trace("Web request was aborted");
            return "aborted";
        } else {
            throw new RuntimeException("Could not contact server", e);
        }
    } finally {
        lock.lock();
        activeSolve.set(false);
        lock.unlock();
    }
}

我有从另一个线程中断的代码

   public void interrupt() {
        lock.lock();
        if (activeSolve.get()) {
            post.abort();
        }
        lock.unlock();
    }

这往往可行,但在大约 1000 个问题的过程中(我发现很难重现,但如果我运行足够长的时间,我最终会看到它),我将得到以下堆栈跟踪:

java.lang.IllegalStateException: Connection is not open
at org.apache.http.util.Asserts.check(Asserts.java:34)
at org.apache.http.impl.BHttpConnectionBase.ensureOpen(BHttpConnectionBase.java:132)
at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseEntity(DefaultBHttpClientConnection.java:177)
at org.apache.http.impl.conn.CPoolProxy.receiveResponseEntity(CPoolProxy.java:172)
at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:274)
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:124)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:271)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:107)
at ... my classes

如果我注释掉中断代码并禁用中断,我就不再看到此错误。但据我所知,我正在正确使用该库。

如果有人熟悉这个库,您能否告诉我我如何错误地使用它,或者哪些事件顺序可能会触发该错误?否则,如果有另一个库可以取消您认为可靠的 http 请求,我就不受这个 apache 库的约束。

最佳答案

我不确定这是否是问题的根源,但 HttpPost 被标记为非线程安全(请参阅 javadoc )。这很可能会给您带来问题,并可能解释您在此处看到的内容。

由于它不是线程安全的,所以很难确切地知道它会如何失败,这甚至可能取决于 JVM 实现。

关于java - Apache Httpclient 中止请求导致错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30743411/

相关文章:

java - Apache httpclient 4.3.3 我如何只接受一个特定的自签名证书

java - 使用 Spring MVC 的 tomcat 中的 PATCH 方法

java - 如何在几周内停止或崩溃 Android 应用程序?

java - AppEngine 上的多部分 POST (Java)

java - 通过 HTTP 代理的 HTTPS

java - 如何在 Android 上使用外部库使用的 Apache http-client 4.5.x

java - 为什么我会收到 TextView.append 运行时异常?

java - 使用JavaFX图表API绘制图表图像

java - 生成调用图的好算法?

java - LG G3 手机的 Android 6.0 HTTPClient 问题