com.aliyun.httpcomponent.httpclient.ApacheAsyncHttpClient Maven / Gradle / Ivy
The newest version!
package com.aliyun.httpcomponent.httpclient;
import com.aliyun.apache.hc.client5.http.async.methods.*;
import com.aliyun.core.http.*;
import com.aliyun.core.logging.ClientLogger;
import com.aliyun.core.utils.BinaryUtils;
import com.aliyun.core.utils.Context;
import com.aliyun.core.utils.StringUtils;
import com.aliyun.httpcomponent.httpclient.implementation.ApacheAsyncHttpResponse;
import com.aliyun.httpcomponent.httpclient.implementation.StreamRequestProducer;
import com.aliyun.httpcomponent.httpclient.implementation.reactive.ReactiveApacheHttpResponse;
import com.aliyun.httpcomponent.httpclient.implementation.reactive.ReactiveHttpResponse;
import com.aliyun.httpcomponent.httpclient.implementation.reactive.ReactiveResponseConsumer;
import com.aliyun.apache.hc.client5.http.config.RequestConfig;
import com.aliyun.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
import com.aliyun.apache.hc.core5.concurrent.FutureCallback;
import com.aliyun.apache.hc.core5.http.ContentType;
import com.aliyun.apache.hc.core5.http.HttpHost;
import com.aliyun.apache.hc.core5.http.nio.AsyncRequestProducer;
import com.aliyun.apache.hc.core5.io.CloseMode;
import com.aliyun.apache.hc.core5.util.TimeValue;
import com.aliyun.apache.hc.core5.util.Timeout;
import java.net.*;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import static com.aliyun.core.http.ProxyOptions.Type.HTTP;
class ApacheAsyncHttpClient implements HttpClient {
private final String RESPONSE_HANDLER_KEY = "RESPONSE_HANDLER";
private final ClientLogger logger = new ClientLogger(ApacheAsyncHttpClient.class);
private final CloseableHttpAsyncClient apacheHttpAsyncClient;
private final Timeout connectTimeout;
private final long connectionKeepAlive;
ApacheAsyncHttpClient(CloseableHttpAsyncClient apacheHttpAsyncClient, Timeout connectTimeout, long connectionKeepAlive) {
this.apacheHttpAsyncClient = apacheHttpAsyncClient;
this.connectTimeout = connectTimeout;
this.connectionKeepAlive = connectionKeepAlive;
}
@Override
public CompletableFuture send(HttpRequest request) {
return send(request, Context.NONE);
}
@Override
public CompletableFuture send(HttpRequest request, Context context) {
apacheHttpAsyncClient.start();
Objects.requireNonNull(request.getHttpMethod(), "'request.getHttpMethod()' cannot be null.");
Objects.requireNonNull(request.getUrl(), "'request.getUrl()' cannot be null.");
Objects.requireNonNull(request.getUrl().getProtocol(), "'request.getUrl().getProtocol()' cannot be null.");
if (context.getData(RESPONSE_HANDLER_KEY).isPresent()
|| request.getStreamBody() != null) {
return sendV2(request, context);
} else {
return sendV1(request, context);
}
}
@Override
public void close() {
if (apacheHttpAsyncClient != null) {
apacheHttpAsyncClient.close(CloseMode.GRACEFUL);
}
}
private SimpleHttpRequest toApacheAsyncRequest(HttpRequest request) throws URISyntaxException, ExecutionException, InterruptedException {
final SimpleRequestBuilder apacheRequestBuilder = SimpleRequestBuilder.create(request.getHttpMethod().toString())
.setUri(request.getUrl().toURI());
final HttpHeaders headers = request.getHeaders();
for (HttpHeader httpHeader : headers) {
apacheRequestBuilder.setHeader(httpHeader.getName(), httpHeader.getValue());
}
switch (request.getHttpMethod()) {
case GET:
case HEAD:
case DELETE:
return apacheRequestBuilder.build();
default:
if (request.getBody() != null) {
ContentType type;
if (StringUtils.isEmpty(headers.getValue("content-type"))) {
type = ContentType.APPLICATION_FORM_URLENCODED;
} else {
String[] ct = headers.getValue("content-type").split(";");
if (ct.length > 1) {
type = ContentType.create(ct[0].trim(), ct[1].replace("charset=", "").trim());
} else {
type = ContentType.create(ct[0].trim());
}
}
apacheRequestBuilder.setBody(BinaryUtils.copyAllBytesFrom(request.getBody()), type);
}
return apacheRequestBuilder.build();
}
}
private AsyncRequestProducer toApacheRequestProducer(HttpRequest request) throws URISyntaxException, ExecutionException, InterruptedException {
SimpleHttpRequest simpleHttpRequest = toApacheAsyncRequest(request);
simpleHttpRequest.setConfig(new ApacheIndividualRequestBuilder(request, connectTimeout, connectionKeepAlive).build());
if (request.getStreamBody() != null) {
return StreamRequestProducer.create(simpleHttpRequest, request.getStreamBody());
} else {
return SimpleRequestProducer.create(simpleHttpRequest);
}
}
private CompletableFuture sendV1(HttpRequest request, Context context) {
SimpleHttpRequest apacheRequest;
try {
apacheRequest = toApacheAsyncRequest(request);
} catch (URISyntaxException | ExecutionException | InterruptedException e) {
throw logger.logExceptionAsWarning(new IllegalArgumentException("'url' must can convert to a valid URI", e));
}
apacheRequest.setConfig(new ApacheIndividualRequestBuilder(request, connectTimeout, connectionKeepAlive).build());
CompletableFuture cf = new CompletableFuture<>();
final Future future = apacheHttpAsyncClient.execute(
apacheRequest,
new FutureCallback() {
@Override
public void completed(SimpleHttpResponse response) {
cf.complete(response);
}
@Override
public void failed(final Exception ex) {
cf.completeExceptionally(ex);
}
@Override
public void cancelled() {
cf.cancel(true);
}
});
return cf.thenApply(simpleHttpResponse ->
new ApacheAsyncHttpResponse(request, simpleHttpResponse));
}
private CompletableFuture sendV2(HttpRequest request, Context context) {
AsyncRequestProducer apacheRequestProducer;
try {
apacheRequestProducer = toApacheRequestProducer(request);
} catch (URISyntaxException | ExecutionException | InterruptedException e) {
throw logger.logExceptionAsWarning(new IllegalArgumentException("'url' must can convert to a valid URI", e));
}
if (context.getData(RESPONSE_HANDLER_KEY).isPresent()) {
CompletableFuture cf = new CompletableFuture<>();
final Future future = apacheHttpAsyncClient.execute(
apacheRequestProducer,
new ReactiveResponseConsumer((HttpResponseHandler) context.getData(RESPONSE_HANDLER_KEY).get()),
new FutureCallback() {
@Override
public void completed(ReactiveApacheHttpResponse response) {
cf.complete(response);
}
@Override
public void failed(final Exception ex) {
cf.completeExceptionally(ex);
}
@Override
public void cancelled() {
cf.cancel(true);
}
});
return cf.thenApply(reactiveHttpResponse ->
new ReactiveHttpResponse(request, reactiveHttpResponse));
} else {
CompletableFuture cf = new CompletableFuture<>();
final Future future = apacheHttpAsyncClient.execute(
apacheRequestProducer,
SimpleResponseConsumer.create(),
new FutureCallback() {
@Override
public void completed(SimpleHttpResponse response) {
cf.complete(response);
}
@Override
public void failed(final Exception ex) {
cf.completeExceptionally(ex);
}
@Override
public void cancelled() {
cf.cancel(true);
}
});
return cf.thenApply(simpleHttpResponse ->
new ApacheAsyncHttpResponse(request, simpleHttpResponse));
}
}
private static final class ApacheIndividualRequestBuilder {
private final ClientLogger logger = new ClientLogger(ApacheIndividualRequestBuilder.class);
private final HttpRequest request;
private final RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();
private final Timeout connectTimeout;
private final long connectionKeepAlive;
public ApacheIndividualRequestBuilder(HttpRequest request, Timeout connectTimeout, long connectionKeepAlive) {
this.request = request;
this.connectTimeout = connectTimeout;
this.connectionKeepAlive = connectionKeepAlive;
}
ApacheIndividualRequestBuilder setConnectTimeout() {
if (request.getConnectTimeout() != null)
requestConfigBuilder.setConnectTimeout(duration2Timeout(request.getConnectTimeout()));
else {
requestConfigBuilder.setConnectTimeout(connectTimeout);
}
return this;
}
ApacheIndividualRequestBuilder setResponseTimeout() {
if (request.getResponseTimeout() != null)
requestConfigBuilder.setResponseTimeout(duration2Timeout(request.getResponseTimeout()));
return this;
}
// if not set, based on setRoutePlanner config
ApacheIndividualRequestBuilder setProxy() {
ProxyOptions proxyOptions = request.getProxyOptions();
if (proxyOptions != null && proxyOptions.getType() == HTTP) {
if (proxyOptions.getNonProxyHosts() == null || !proxyOptions.getNonProxyHosts().contains(request.getUrl().getHost())) {
InetSocketAddress inetSocketAddress = proxyOptions.getAddress();
requestConfigBuilder.setProxy(new HttpHost(
proxyOptions.getScheme(),
inetSocketAddress.getAddress(),
inetSocketAddress.getHostString(),
inetSocketAddress.getPort()
));
} else {
requestConfigBuilder.setProxy(null);
}
}
return this;
}
RequestConfig build() {
this.setConnectTimeout().setResponseTimeout().setProxy();
return requestConfigBuilder.setConnectionKeepAlive(TimeValue.of(connectionKeepAlive, TimeUnit.MILLISECONDS)).build();
}
private Timeout duration2Timeout(Duration duration) {
return Timeout.ofMilliseconds(duration.toMillis());
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy