繁体   English   中英

Apache HttpClient中止请求导致错误

[英]Apache Httpclient abort requests causing error

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

我最初使用的是Spring的RestTemplate,但找不到此功能。 最终,我偶然发现了Apache的httpclient(我正在使用org.apache.httpcomponents:httpclient:4.4.1)。 Apache Httpclient表示它可以中止请求 ,因此我按如下方式使用它:

    // 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实现。

  • 如果您稍微改变了方法,并从线程池中产生了线程,则一旦获得响应,您就可以关闭该池。
  • 如果在上述方法中我没记错,我会看到HttpClient的实例是共享的,请尝试在关键部分(方法)内移动该实例,然后查看导致上述问题的中断已消失。
  • 在中断方法中,原子变量的使用非常有用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM