Apache-Httpclient重试工具类封装
- pom依赖
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpcore</artifactId> <version>4.4.4</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.7</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.76</version> </dependency>
- Http属性常量
package com.coolw.codedemo.http; /** * @Description Http 属性请求常量 * @Date 2021/5/11 11:46 * @Author coolw */ public interface HttpConstants { /** * 连接池最大连接数 */ int MAX_TOTAL_POOL = 256; /** * 每路连接最多连接数 */ int MAX_CONPERROUTE = 32; /** * socket超时时间 */ int SOCKET_TIMEOUT = 60 * 1000; /** * 连接请求超时时间 */ int CONNECTION_REQUEST_TIMEOUT = 5 * 1000; /** * 连接超时时间 */ int CONNECT_TIMEOUT = 5 * 1000; /** * http协议 */ String HTTP_PROTOCOL = "http"; /** * https协议 */ String HTTPS_PROTOCOL = "https"; /** * TLS */ String SSL_CONTEXT = "TLS"; /** * utf-8编码 */ String CHARSET_UTF_8 = "UTF-8"; /** * application/json */ String CONTENT_TYPE_JSON = "application/json"; /** * content-type */ String CONTENT_TYPE = "Content-Type"; }
- Http请求类型
package com.coolw.codedemo.http; /** * @Description Http请求类型 * @Date 2021/5/11 12:21 * @Author coolw */ public enum HttpMethod { GET, POST }
- Http请求公共配置
package com.coolw.codedemo.http; import org.apache.commons.lang3.StringUtils; import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.entity.StringEntity; import java.util.Map; /** * @Description Http请求公共配置 * @Date 2021/5/11 11:45 * @Author coolw */ public class HttpRequestConfig { /** * 返回默认的content-type: application/json */ protected static String getDefaultContentType() { return HttpConstants.CONTENT_TYPE_JSON; } /** * 设置默认的content-Type:application/json */ protected static void setContentTypeApplicationJson(HttpRequestBase requestBase) { requestBase.setHeader(HttpConstants.CONTENT_TYPE, HttpConstants.CONTENT_TYPE_JSON); } /** * 设置content-Type */ protected static void setContentType(HttpRequestBase httpBase, String contentType) { if (StringUtils.isBlank(contentType)) { contentType = getDefaultContentType(); } httpBase.setHeader(HttpConstants.CONTENT_TYPE, contentType); } /** * 设置请求体 */ protected static void setHttpBody(HttpEntityEnclosingRequestBase httpRequest, String body) { if (StringUtils.isBlank(body)) { return; } StringEntity entity = new StringEntity(body, HttpConstants.CHARSET_UTF_8); entity.setContentEncoding(HttpConstants.CHARSET_UTF_8); entity.setContentType(HttpConstants.CHARSET_UTF_8); httpRequest.setEntity(entity); } /** * 设置头部参数 */ protected static void setHeader(HttpRequestBase httpBase, Map<String, String> headerMap) { if (headerMap == null || headerMap.size() == 0) { return; } for (Map.Entry<String, String> entry : headerMap.entrySet()) { httpBase.addHeader(entry.getKey(), entry.getValue()); } } }
- Http连接工厂
package com.coolw.codedemo.http; import org.apache.http.client.config.RequestConfig; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; /** * @Description HttpClient 连接工厂 * @Date 2021/5/11 12:26 * @Author coolw */ public class HttpClientConnectFactory { private static PoolingHttpClientConnectionManager cm = null; /** * 初始化连接池 */ static { SSLContext sslcontext; try { sslcontext = createIgnoreVerifySSL(); ConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory(); Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create() .register(HttpConstants.HTTP_PROTOCOL, plainsf) .register(HttpConstants.HTTPS_PROTOCOL, getSSLConnectionSocketFactory(sslcontext)) .build(); cm = new PoolingHttpClientConnectionManager(registry); cm.setMaxTotal(HttpConstants.MAX_TOTAL_POOL); cm.setDefaultMaxPerRoute(HttpConstants.MAX_CONPERROUTE); } catch (Exception e) { e.getStackTrace(); } } /** * 获取 HttpClient 连接 */ public static CloseableHttpClient getHttpClient() { RequestConfig requestConfig = RequestConfig.custom() .setConnectionRequestTimeout(HttpConstants.CONNECTION_REQUEST_TIMEOUT) .setConnectTimeout(HttpConstants.CONNECT_TIMEOUT) .setSocketTimeout(HttpConstants.SOCKET_TIMEOUT) .build(); CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm) .setDefaultRequestConfig(requestConfig) .setRetryHandler(new HttpRequestRetryHandler()) .setConnectionManagerShared(true) .build(); return httpClient; } /** * 创建 SSLContext */ private static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException { SSLContext sc = SSLContext.getInstance(HttpConstants.SSL_CONTEXT); X509TrustManager trustManager = new X509TrustManager() { @Override public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { } @Override public X509Certificate[] getAcceptedIssuers() { return null; } }; sc.init(null, new TrustManager[]{trustManager}, null); return sc; } /** * 获取 SSLConnectionSocketFactory */ private static ConnectionSocketFactory getSSLConnectionSocketFactory(SSLContext sslcontext) { return new SSLConnectionSocketFactory(sslcontext, NoopHostnameVerifier.INSTANCE); } }
- Http重试处理
package com.coolw.codedemo.http; import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpRequest; import org.apache.http.NoHttpResponseException; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; import org.apache.http.protocol.HttpContext; import javax.net.ssl.SSLException; import javax.net.ssl.SSLHandshakeException; import java.io.IOException; import java.io.InterruptedIOException; import java.net.UnknownHostException; /** * @Description Http重试处理机制 * @Date 2021/5/11 10:20 * @Author coolw */ public class HttpRequestRetryHandler extends DefaultHttpRequestRetryHandler { /** * 重试次数,默认3次 */ private int retryCount = 3; public HttpRequestRetryHandler() { super(); } public HttpRequestRetryHandler(int retryCount) { super(); this.retryCount = retryCount; } @Override public boolean retryRequest(IOException exception, int executionCount, HttpContext context) { // 重试次数已上限,不重试 if (executionCount >= retryCount) { return false; } if (exception instanceof SSLHandshakeException) { return false; } if (exception instanceof UnknownHostException) { return false; } if (exception instanceof SSLException) { return false; } // 重试 if (exception instanceof NoHttpResponseException) { return true; } if (exception instanceof InterruptedIOException) { return true; } HttpClientContext clientContext = HttpClientContext.adapt(context); HttpRequest request = clientContext.getRequest(); // 如果请求是幂等的,重试 if (!(request instanceof HttpEntityEnclosingRequest)) { return true; } return false; } }
- Http工具类
package com.coolw.codedemo.http; import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpStatus; import org.apache.http.client.methods.*; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.util.EntityUtils; import java.io.IOException; import java.lang.reflect.Type; import java.util.Map; /** * @Description Http工具类 * @Date 2021/5/11 12:17 * @Author coolw */ @Slf4j public class BaseHttpUtils extends HttpRequestConfig { /** * 创建Http请求对象 */ protected static HttpRequestBase createHttpRequestBase(HttpMethod method, String url) { switch (method) { case GET: return new HttpGet(url); case POST: return new HttpPost(url); default: return new HttpGet(url); } } protected static String exec(String url, HttpMethod method, Map<String, String> headerMap, String contentType, String body) { HttpRequestBase httpRequest = createHttpRequestBase(method, url); setHeader(httpRequest, headerMap); setContentType(httpRequest, contentType); if (httpRequest instanceof HttpEntityEnclosingRequestBase) { setHttpBody((HttpEntityEnclosingRequestBase) httpRequest, body); } CloseableHttpResponse response = null; try (CloseableHttpClient httpClient = HttpClientConnectFactory.getHttpClient()) { response = httpClient.execute(httpRequest); int statusCode = response.getStatusLine().getStatusCode(); if (statusCode == HttpStatus.SC_OK) { return EntityUtils.toString(response.getEntity(), "utf-8"); } log.warn("http exec status fail. url={},statusCode={}", url, statusCode); } catch (IOException e) { log.error("http exec error. url:{},body={}", url, body, e); } return JSON.toJSONString(response); } @SuppressWarnings("unchecked") public static <T> T responseHandle(String apiResult, T defaultResult, Type type) { if (StringUtils.isBlank(apiResult)) { return defaultResult; } try { return (T) JSON.parseObject(apiResult, type); } catch (Exception e) { return defaultResult; } } }
- Http多参工具类
package com.coolw.codedemo.http; import java.util.Map; /** * @Description 多参Http工具类 * @Date 2021/5/11 13:54 * @Author coolw */ public class MultiHttpUtils extends BaseHttpUtils { /** * exec请求。content-Type 默认 application/json * * @param method 请求类型 * @param url 请求地址 * @return String */ public static String exec(HttpMethod method, String url) { return exec(method, url, null, getDefaultContentType(), null); } /** * exec请求,通过以下参数获取数据 * * @param method 请求类型 * @param url 请求地址 * @param headerMap 请求头部参数 * @return String */ public static String exec(HttpMethod method, String url, Map<String, String> headerMap) { return exec(method, url, headerMap, getDefaultContentType(), null); } /** * exec请求。content-Type 默认 application/json * * @param method 请求类型 * @param url 请求地址 * @param body 请求内容 * @return String */ public static String exec(HttpMethod method, String url, String body) { return exec(method, url, null, getDefaultContentType(), body); } /** * exec请求 * * @param method 请求类型 * @param url 请求地址 * @param contentType 请求内容体类型 * @param body 请求内容 * @return String */ public static String exec(HttpMethod method, String url, String contentType, String body) { return exec(method, url, null, contentType, body); } /** * exec请求。content-Type 默认 application/json * * @param method 请求类型 * @param url 请求地址 * @param headerMap 请求头部参数 * @param body 请求内容 * @return String */ public static String exec(HttpMethod method, String url, Map<String, String> headerMap, String body) { return exec(method, url, headerMap, getDefaultContentType(), body); } /** * exec请求 * * @param method 请求类型 * @param url 请求地址 * @param headerMap 请求头部参数 * @param contentType 请求内容体类型 * @param body 请求内容 * @return String */ public static String exec(HttpMethod method, String url, Map<String, String> headerMap, String contentType, String body) { return exec(url, method, headerMap, contentType, body); } }