我在使用 apache http 客户端从我的 Web 应用程序对第三方系统进行 http 调用时遇到问题。我正在使用 http-core-4.4.4 和 http-client-4.5.1。此票证HTTPCORE-446表明死锁问题已解决,并在异常情况下正常终止线程。有没有人遇到过这个异常,对导致这个问题的原因以及如何解决这个问题有任何想法吗?
编辑:用于进行 http 调用的 Http 代码片段
protected <ResponseObj> run() throws Exception {
String uri = <target system uri>;
HttpPost httpPost = new HttpPost(uri);
final HttpEntity entity = <Built http entity obj>;
httpPost.setEntity(entity);
HttpClient client = HttpClientBuilder.create().build();
try {
final HttpResponse response = client.execute(httpPost);
ResponseObj res = processResponse(response);
return res;
} catch (Exception e) {
LOGGER.error(ERROR_CALLING_TARGET, e);
throw new CustomException(e);
}
}
Run Code Online (Sandbox Code Playgroud)
例外
org.apache.http.impl.execchain.RequestAbortedException: Request aborted
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:193) ~[httpclient-4.5.1.jar:4.5.1]
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184) ~[httpclient-4.5.1.jar:4.5.1]
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88) ~[httpclient-4.5.1.jar:4.5.1]
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110) ~[httpclient-4.5.1.jar:4.5.1]
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184) ~[httpclient-4.5.1.jar:4.5.1]
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82) ~[httpclient-4.5.1.jar:4.5.1]
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:107) ~[httpclient-4.5.1.jar:4.5.1]
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:55) ~[httpclient-4.5.1.jar:4.5.1]
at com.netflix.hystrix.HystrixCommand$1.call(HystrixCommand.java:294) [hystrix-core-1.4.26.jar:1.4.26]
at com.netflix.hystrix.HystrixCommand$1.call(HystrixCommand.java:289) [hystrix-core-1.4.26.jar:1.4.26]
at rx.Observable$2.call(Observable.java:162) [rxjava-1.1.1.jar:1.1.1]
at rx.Observable$2.call(Observable.java:154) [rxjava-1.1.1.jar:1.1.1]
at rx.Observable$2.call(Observable.java:162) [rxjava-1.1.1.jar:1.1.1]
at rx.Observable$2.call(Observable.java:154) [rxjava-1.1.1.jar:1.1.1]
at rx.Observable$2.call(Observable.java:162) [rxjava-1.1.1.jar:1.1.1]
at rx.Observable$2.call(Observable.java:154) [rxjava-1.1.1.jar:1.1.1]
at rx.Observable.unsafeSubscribe(Observable.java:8314) [rxjava-1.1.1.jar:1.1.1]
at com.netflix.hystrix.AbstractCommand$5.call(AbstractCommand.java:521) [hystrix-core-1.4.26.jar:1.4.26]
at com.netflix.hystrix.AbstractCommand$5.call(AbstractCommand.java:499) [hystrix-core-1.4.26.jar:1.4.26]
at rx.Observable.unsafeSubscribe(Observable.java:8314) [rxjava-1.1.1.jar:1.1.1]
at rx.internal.operators.OperatorSubscribeOn$1.call(OperatorSubscribeOn.java:94) [rxjava-1.1.1.jar:1.1.1]
at com.netflix.hystrix.strategy.concurrency.HystrixContexSchedulerAction$1.call(HystrixContexSchedulerAction.java:56) [hystrix-core-1.4.26.jar:1.4.26]
at com.netflix.hystrix.strategy.concurrency.HystrixContexSchedulerAction$1.call(HystrixContexSchedulerAction.java:47) [hystrix-core-1.4.26.jar:1.4.26]
at com.netflix.hystrix.strategy.concurrency.HystrixContexSchedulerAction.call(HystrixContexSchedulerAction.java:69) [hystrix-core-1.4.26.jar:1.4.26]
at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55) [rxjava-1.1.1.jar:1.1.1]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_51]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_51]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_51]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_51]
at java.lang.Thread.null(Unknown Source) [na:1.8.0_51]
Caused by: java.lang.InterruptedException: null
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.reportInterruptAfterWait(AbstractQueuedSynchronizer.java:2014) ~[na:1.8.0_51]
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2048) ~[na:1.8.0_51]
at org.apache.http.pool.PoolEntryFuture.await(PoolEntryFuture.java:138) ~[httpcore-4.4.4.jar:4.4.4]
at org.apache.http.pool.AbstractConnPool.getPoolEntryBlocking(AbstractConnPool.java:306) ~[httpcore-4.4.4.jar:4.4.4]
at org.apache.http.pool.AbstractConnPool.access$000(AbstractConnPool.java:64) ~[httpcore-4.4.4.jar:4.4.4]
at org.apache.http.pool.AbstractConnPool$2.getPoolEntry(AbstractConnPool.java:192) ~[httpcore-4.4.4.jar:4.4.4]
at org.apache.http.pool.AbstractConnPool$2.getPoolEntry(AbstractConnPool.java:185) ~[httpcore-4.4.4.jar:4.4.4]
at org.apache.http.pool.PoolEntryFuture.get(PoolEntryFuture.java:107) ~[httpcore-4.4.4.jar:4.4.4]
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.leaseConnection(PoolingHttpClientConnectionManager.java:276) ~[httpclient-4.5.1.jar:4.5.1]
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager$1.get(PoolingHttpClientConnectionManager.java:263) ~[httpclient-4.5.1.jar:4.5.1]
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:190) ~[httpclient-4.5.1.jar:4.5.1]
... 32 common frames omitted
Run Code Online (Sandbox Code Playgroud)
我刚刚遇到了类似的问题,我想我也可以提供一些提示来解决您的问题。
我有一个 HttpClient 定期调用服务器,事实证明它应答调用的速度非常慢。当调度程序启动请求 N+1 时,请求 N 仍在等待响应。
如果您查看堆栈跟踪底部显示的 MainClientExec ln190 的源代码,您可以看到 ConnectionRequest.get() 调用抛出了原始的 InterruptedException,该异常被捕获、包装到 RequestAbortedException 中并重新抛出。引用 ConnectionRequest.get() 方法 javadoc:
在给定时间内获得连接。此方法将阻塞,直到连接可用、超时到期或连接管理器关闭。超时以毫秒精度处理。如果在阻塞时或开始之前调用 Cancellable.cancel(),则会抛出 InterruptedException。
那么,在我们的线程上调用cancel()的是什么东西呢?对我来说,它看起来像是另一个线程执行相同的 MainClientExec.execute() 方法,可能以相同的方式设置请求。仅在 try-catch 块上方几行:
final ConnectionRequest connRequest = connManager.requestConnection(route, userToken);
if (execAware != null) {
if (execAware.isAborted()) {
connRequest.cancel();
throw new RequestAbortedException("Request aborted");
} else {
execAware.setCancellable(connRequest);
}
}
Run Code Online (Sandbox Code Playgroud)
我的猜测是,如果之前的 HTTP 调用仍在进行中,则此代码会取消该调用。
所以,就我而言,根本问题是服务器速度慢(需要几分钟才能响应)。我的解决方案是设置连接和请求超时值。默认情况下,HttpClient 没有设置超时,您必须手动设置。请参阅此答案以获取有关如何执行此操作的工作示例。现在,在触发下一个计划调用之前,我的 HTTP 请求遇到超时。当服务器响应缓慢时,我仍然会遇到错误,但超时异常更容易理解。
| 归档时间: |
|
| 查看次数: |
2763 次 |
| 最近记录: |