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);
    }

}

 

posted @ 2021-05-20 12:04  coolw  阅读(355)  评论(0编辑  收藏  举报