com.feingto.cloud.kit.http.ApacheHttpClient Maven / Gradle / Ivy
package com.feingto.cloud.kit.http;
import lombok.Data;
import lombok.SneakyThrows;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.apache.http.NameValuePair;
import org.apache.http.client.fluent.Request;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.message.BasicNameValuePair;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.util.StreamUtils;
import java.io.InputStream;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
/**
* Apache Http Fluent 客户端
*
* @author longfei
*/
@Slf4j
@Data
@Accessors(fluent = true)
public class ApacheHttpClient {
private static final Integer DEFAULT_REQUEST_TIMEOUT = 30;
private HttpMethod method = HttpMethod.GET;
private Map headers = new HashMap<>();
/**
* 超时秒数, 默认60秒
*/
private int timeout = DEFAULT_REQUEST_TIMEOUT;
/**
* 重试次数
*/
private int retry = 0;
public ClientResponse invoke(String url) {
return this.invoke(url, new HashMap<>());
}
public ClientResponse invoke(String url, Map params) {
Request request;
switch (this.method) {
case GET:
return this.invoke(Request.Get(this.buildUri(url, params)));
case POST:
request = Request.Post(url);
if (MapUtils.isNotEmpty(params)) {
request.bodyForm(this.buildFormParams(params), StandardCharsets.UTF_8);
}
return this.invoke(request);
case PUT:
request = Request.Put(url);
if (MapUtils.isNotEmpty(params)) {
request.bodyForm(this.buildFormParams(params), StandardCharsets.UTF_8);
}
return this.invoke(request);
case DELETE:
return this.invoke(Request.Delete(this.buildUri(url, params)));
}
return ClientResponse.badRequest();
}
public ClientResponse invoke(String url, byte[] bytes, ContentType contentType) {
if (HttpMethod.POST == this.method) {
Request request = Request.Post(url).bodyByteArray(bytes, contentType.withCharset(StandardCharsets.UTF_8));
return this.invoke(request);
}
if (HttpMethod.PUT == this.method) {
Request request = Request.Put(url).bodyByteArray(bytes, contentType.withCharset(StandardCharsets.UTF_8));
return this.invoke(request);
}
return ClientResponse.badRequest();
}
public ClientResponse invoke(String url, InputStream inputStream) {
if (HttpMethod.POST == this.method) {
return this.invoke(Request.Post(url), inputStream);
}
if (HttpMethod.PUT == this.method) {
return this.invoke(Request.Put(url), inputStream);
}
return ClientResponse.badRequest();
}
private ClientResponse invoke(Request request, InputStream inputStream) {
request = request.bodyStream(inputStream, ContentType.MULTIPART_FORM_DATA.withCharset(StandardCharsets.UTF_8));
return this.invoke(request);
}
private ClientResponse invoke(Request request) {
request.connectTimeout(timeout * 1000).socketTimeout(timeout * 1000).useExpectContinue();
if (MapUtils.isNotEmpty(headers)) {
headers.forEach(request::addHeader);
}
try {
org.apache.http.HttpResponse response = request.execute().returnResponse();
HttpHeaders httpHeaders = new HttpHeaders();
Arrays.stream(response.getAllHeaders()).forEach(it -> httpHeaders.add(it.getName(), it.getValue()));
return new ClientResponse()
.setStatusCode(response.getStatusLine().getStatusCode())
.setBody(Objects.nonNull(response.getEntity()) ? response.getEntity().getContent() : StreamUtils.emptyInput())
.setHeaders(httpHeaders)
.setSuccessful(response.getStatusLine().getStatusCode() == HttpStatus.OK.value());
} catch (Exception e) {
if (retry > 0) {
log.debug("The request failed and retried {} times", retry);
retry -= 1;
this.invoke(request);
}
log.error("Request internal error: invalid service url", e);
return Optional.of(e)
.filter(it -> it instanceof SocketTimeoutException)
.map(it -> ClientResponse.requestTimeout())
.orElse(ClientResponse.error("Request internal error: invalid service url"));
}
}
private Iterable extends NameValuePair> buildFormParams(Map params) {
return params.keySet().stream()
.map(key -> new BasicNameValuePair(key, params.get(key)))
.collect(Collectors.toList());
}
@SneakyThrows
private URI buildUri(String url, Map params) {
URIBuilder uri = new URIBuilder(url);
if (MapUtils.isNotEmpty(params)) {
params.forEach(uri::addParameter);
}
return uri.build();
}
}