没有收到 Http 异步客户端的响应
Not getting response with Http Async Client
我遇到了这种奇怪的情况,有时我的 HTTP 请求没有发出,或者我偶尔没有收到对我的请求的 HTTP 响应。我的应用程序定期向其他第 3 方服务发出几个(100 秒)http 请求,其中大部分都工作得很好。
我使用带有自定义 HttpRequestIntercerptor 和 HttpResponseInterceptor 的 CloseableHttpAsyncClient(版本 4.0)。添加这些主要是为了调试目的,RequestInterceptor 是链中的最后一个拦截器,而 ResponseInterceptor 是第一个。这个想法是在发送实际请求之前的最后阶段记录每个 http 请求,并在第一次收到时记录每个 http 响应。
我有以下模式来设置异步客户端:
HttpAsyncClientBuilder asyncClientBuilder = HttpAsyncClientBuilder.create();
asyncClientBuilder.addInterceptorLast(new MyHttpRequestInterceptor());
asyncClientBuilder.addInterceptorFirst(new MyHttpResponseInterceptor());
IOReactorConfig reactorConfig = IOReactorConfig.DEFAULT;
reactorConfig.setConnectTimeout(5 * 60 * 1000); // 5 mins
reactorConfig.setSoTimeout(5 * 60 * 1000); // 5 mins
asyncClientBuilder.setDefaultIOReactorConfig(reactorConfig);
System.setProperty("http.maxConnections", "100");
this.asyncHttpClient = asyncClientBuilder.useSystemProperties().build();
this.asyncHttpClient.start();
要提出我的要求:
HttpGet httpGet = new HttpGet("some url");
asyncHttpClient.execute(httpGet, new AsyncHTTPResponseHandler(requestMetadata));
这是我的 AsyncHTTPResponseHandler class:
class AsyncHTTPResponseHandler implements FutureCallback<HttpResponse> {
// local copy of the request for reference while processing the response.
private RequestMetadata requestMetadata;
public AsyncHTTPResponseHandler(final RequestMetadata requestMetadata) {
this.setRequestMetadata(requestMetadata);
Thread.currentThread().setUncaughtExceptionHandler(new HttpUncaughtExceptionHandler(requestMetadata));
}
@Override
public void cancelled() {
logger.error("AsyncHTTPResponseHandler#Http request id: {} cancelled",
requestMetadata.getRequestId()));
}
@Override
public void completed(HttpResponse response) {
logger.debug("Received HTTP Response for request id: {}",
requestMetadata.getRequestId());
//handleHttpResponse(requestMetadata, response);
}
@Override
public void failed(Exception e) {
logger.error("AsyncHTTPResponseHandler#Error in Http request id: " + requestMetadata.getRequestId(), e);
}
}
基于此设置,根据我的拦截器日志,我看到了以下情况:
1. 我的应用程序 http 请求触发了异步客户端 HttpRequest,我得到了 HttpResponse——成功。
2. 我的应用程序 http 请求触发了一个 asyncclient HttpRequest(拦截器记录了它),我没有得到这个请求的 HttpResponse --- 不知道为什么?
3. 我的应用程序 http 请求没有触发 asyncclient HttpRequest(拦截器没有记录它)而且我没有得到这个请求的 HttpResponse --- 不知道为什么?
有什么提示或建议可以解决这个问题或进一步调试这个问题吗?
谢谢!!
所以,我想在这里分享我的发现和解决方案。
我们遇到了类似于此错误的症状:https://issues.apache.org/jira/browse/HTTPASYNC-79
如果您为 "org.apache.http.impl.nio" 包启用 DEBUG 日志记录,那么您可以看到交换。注意:日志将非常冗长。
问题已通过将 HttpAsyncClient 库从 4.0 升级到 4.0.2 得到解决。我还启用了套接字和连接超时。您应该在日志文件中看到超时异常。
这是我的 HttpAsyncClient 实例现在的样子:
HttpAsyncClientBuilder asyncClientBuilder = HttpAsyncClientBuilder.create();
asyncClientBuilder.addInterceptorLast(new MyHttpRequestInterceptor());
asyncClientBuilder.addInterceptorFirst(new MyHttpResponseInterceptor());
// reactor config
IOReactorConfig reactorConfig = IOReactorConfig.custom()
.setConnectTimeout(TIMEOUT_5_MINS_IN_MILLIS)
.setSoTimeout(TIMEOUT_5_MINS_IN_MILLIS).build();
asyncClientBuilder.setDefaultIOReactorConfig(reactorConfig);
// request config
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(TIMEOUT_5_MINS_IN_MILLIS)
.setConnectionRequestTimeout(TIMEOUT_5_MINS_IN_MILLIS)
.setSocketTimeout(TIMEOUT_5_MINS_IN_MILLIS).build();
asyncClientBuilder.setDefaultRequestConfig(requestConfig);
// connection config
ConnectionConfig connectionConfig = ConnectionConfig.custom()
.setMalformedInputAction(CodingErrorAction.IGNORE)
.setUnmappableInputAction(CodingErrorAction.IGNORE)
.build();
asyncClientBuilder.setDefaultConnectionConfig(connectionConfig);
System.setProperty("http.maxConnections", "100");
System.setProperty("http.conn-manager.timeout", "300000"); // 5 mins
this.asyncHttpClient = asyncClientBuilder.useSystemProperties().build();
我遇到了这种奇怪的情况,有时我的 HTTP 请求没有发出,或者我偶尔没有收到对我的请求的 HTTP 响应。我的应用程序定期向其他第 3 方服务发出几个(100 秒)http 请求,其中大部分都工作得很好。 我使用带有自定义 HttpRequestIntercerptor 和 HttpResponseInterceptor 的 CloseableHttpAsyncClient(版本 4.0)。添加这些主要是为了调试目的,RequestInterceptor 是链中的最后一个拦截器,而 ResponseInterceptor 是第一个。这个想法是在发送实际请求之前的最后阶段记录每个 http 请求,并在第一次收到时记录每个 http 响应。
我有以下模式来设置异步客户端:
HttpAsyncClientBuilder asyncClientBuilder = HttpAsyncClientBuilder.create();
asyncClientBuilder.addInterceptorLast(new MyHttpRequestInterceptor());
asyncClientBuilder.addInterceptorFirst(new MyHttpResponseInterceptor());
IOReactorConfig reactorConfig = IOReactorConfig.DEFAULT;
reactorConfig.setConnectTimeout(5 * 60 * 1000); // 5 mins
reactorConfig.setSoTimeout(5 * 60 * 1000); // 5 mins
asyncClientBuilder.setDefaultIOReactorConfig(reactorConfig);
System.setProperty("http.maxConnections", "100");
this.asyncHttpClient = asyncClientBuilder.useSystemProperties().build();
this.asyncHttpClient.start();
要提出我的要求:
HttpGet httpGet = new HttpGet("some url");
asyncHttpClient.execute(httpGet, new AsyncHTTPResponseHandler(requestMetadata));
这是我的 AsyncHTTPResponseHandler class:
class AsyncHTTPResponseHandler implements FutureCallback<HttpResponse> {
// local copy of the request for reference while processing the response.
private RequestMetadata requestMetadata;
public AsyncHTTPResponseHandler(final RequestMetadata requestMetadata) {
this.setRequestMetadata(requestMetadata);
Thread.currentThread().setUncaughtExceptionHandler(new HttpUncaughtExceptionHandler(requestMetadata));
}
@Override
public void cancelled() {
logger.error("AsyncHTTPResponseHandler#Http request id: {} cancelled",
requestMetadata.getRequestId()));
}
@Override
public void completed(HttpResponse response) {
logger.debug("Received HTTP Response for request id: {}",
requestMetadata.getRequestId());
//handleHttpResponse(requestMetadata, response);
}
@Override
public void failed(Exception e) {
logger.error("AsyncHTTPResponseHandler#Error in Http request id: " + requestMetadata.getRequestId(), e);
}
}
基于此设置,根据我的拦截器日志,我看到了以下情况: 1. 我的应用程序 http 请求触发了异步客户端 HttpRequest,我得到了 HttpResponse——成功。 2. 我的应用程序 http 请求触发了一个 asyncclient HttpRequest(拦截器记录了它),我没有得到这个请求的 HttpResponse --- 不知道为什么? 3. 我的应用程序 http 请求没有触发 asyncclient HttpRequest(拦截器没有记录它)而且我没有得到这个请求的 HttpResponse --- 不知道为什么?
有什么提示或建议可以解决这个问题或进一步调试这个问题吗?
谢谢!!
所以,我想在这里分享我的发现和解决方案。
我们遇到了类似于此错误的症状:https://issues.apache.org/jira/browse/HTTPASYNC-79
如果您为 "org.apache.http.impl.nio" 包启用 DEBUG 日志记录,那么您可以看到交换。注意:日志将非常冗长。
问题已通过将 HttpAsyncClient 库从 4.0 升级到 4.0.2 得到解决。我还启用了套接字和连接超时。您应该在日志文件中看到超时异常。
这是我的 HttpAsyncClient 实例现在的样子:
HttpAsyncClientBuilder asyncClientBuilder = HttpAsyncClientBuilder.create();
asyncClientBuilder.addInterceptorLast(new MyHttpRequestInterceptor());
asyncClientBuilder.addInterceptorFirst(new MyHttpResponseInterceptor());
// reactor config
IOReactorConfig reactorConfig = IOReactorConfig.custom()
.setConnectTimeout(TIMEOUT_5_MINS_IN_MILLIS)
.setSoTimeout(TIMEOUT_5_MINS_IN_MILLIS).build();
asyncClientBuilder.setDefaultIOReactorConfig(reactorConfig);
// request config
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(TIMEOUT_5_MINS_IN_MILLIS)
.setConnectionRequestTimeout(TIMEOUT_5_MINS_IN_MILLIS)
.setSocketTimeout(TIMEOUT_5_MINS_IN_MILLIS).build();
asyncClientBuilder.setDefaultRequestConfig(requestConfig);
// connection config
ConnectionConfig connectionConfig = ConnectionConfig.custom()
.setMalformedInputAction(CodingErrorAction.IGNORE)
.setUnmappableInputAction(CodingErrorAction.IGNORE)
.build();
asyncClientBuilder.setDefaultConnectionConfig(connectionConfig);
System.setProperty("http.maxConnections", "100");
System.setProperty("http.conn-manager.timeout", "300000"); // 5 mins
this.asyncHttpClient = asyncClientBuilder.useSystemProperties().build();