HttpClient 常用方法封裝

簡介

在平時寫代碼中,經常需要對接口進行訪問,對於 http 協議 rest 風格的接口請求,大多使用 HttpClient 工具進行編寫,想着方便就尋思着把一些常用的方法進行封裝,便於平時快速的使用。

以下代碼封裝的常用方法,支持了http 和 https 兩種協議。

封裝代碼

import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URIBuilder;
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.SSLConnectionSocketFactory;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @Description: httpclient常用方法封裝,
 * @Author: ggf
 * @Date: 2020/06/06
 */
public class HttpClientUtils {
    /**
     * 編碼方式
     */
    private static final String ENCODING = "UTF-8";
    /**
     * 連接超時時間,60秒
     */
    public static final int DEFAULT_CONNECT_TIMEOUT = 6000;
    /**
     * socket連接超時時間,60秒
     */
    public static final int DEFAULT_READ_TIMEOUT = 6000;
    /**
     * 請求超時時間,60秒
     */
    public static final int DEFAULT_CONNECT_REQUEST_TIMEOUT = 6000;
    /**
     * 最大連接數,默認為2
     */
    private static final int MAX_TOTAL = 64;
    /**
     * 設置指向特定路由的並發連接總數,默認為2
     */
    private static final int MAX_PER_ROUTE = 32;

    private static RequestConfig requestConfig;
    private static PoolingHttpClientConnectionManager connectionManager;
    private static BasicCookieStore cookieStore;
    private static HttpClientBuilder httpBuilder;
    private static CloseableHttpClient httpClient;
    private static CloseableHttpClient httpsClient;
    private static SSLContext sslContext;

    /**
     * 創建SSLContext對象,用來繞過https證書認證實現訪問。
     */
    static {
        try {
            sslContext = SSLContext.getInstance("TLS");
            // 實現一個X509TrustManager接口,用於繞過驗證,不用修改裏面的方法
            X509TrustManager tm = new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType)
                        throws CertificateException {
                }
                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType)
                        throws CertificateException {
                }
                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            };
            sslContext.init(null, new TrustManager[] {tm}, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 初始化httpclient對象,以及在創建httpclient對象之前的一些自定義配置。
     */
    static {
        // 自定義配置信息
        requestConfig = RequestConfig.custom()
                .setSocketTimeout(DEFAULT_READ_TIMEOUT)
                .setConnectTimeout(DEFAULT_CONNECT_TIMEOUT)
                .setConnectionRequestTimeout(DEFAULT_CONNECT_REQUEST_TIMEOUT)
                .build();
        //設置協議http和https對應的處理socket鏈接工廠的對象
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
                .register("http", new PlainConnectionSocketFactory())
                .register("https", new SSLConnectionSocketFactory(sslContext))
                .build();
        connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
        // 設置cookie存儲對像,在需要獲取cookie信息時,可以使用這個對象。
        cookieStore = new BasicCookieStore();
        // 設置最大連接數
        connectionManager.setMaxTotal(MAX_TOTAL);
        // 設置路由並發數
        connectionManager.setDefaultMaxPerRoute(MAX_PER_ROUTE);
        httpBuilder = HttpClientBuilder.create();
        httpBuilder.setDefaultRequestConfig(requestConfig);
        httpBuilder.setConnectionManager(connectionManager);
        httpBuilder.setDefaultCookieStore(cookieStore);
        // 實例化http 和 https的對象。
        httpClient = httpBuilder.build();
        httpsClient = httpBuilder.build();
    }

    /**
     * 封裝無參數的get請求(http)
     * @param url 請求url
     * @return 返回對象HttpClientResult
     */
    public static HttpClientResult doGet(String url) {
        return doGet(url, false);
    }

    /**
     * 封裝無參get請求,支持https協議
     * @param url 請求url
     * @param https 請求的是否是https協議,是:true  否false
     * @return
     */
    public static HttpClientResult doGet(String url, boolean https){
        return doGet(url, null, null, https);
    }

    /**
     * 封裝帶參數的get請求,支持https協議
     * @param url 請求url
     * @param params 請求參數
     * @param https 是否是https協議
     */
    public static HttpClientResult doGet(String url, Map<String, String> params, boolean https){
        return doGet(url, null, params, https);
    }

    /**
     * 封裝帶參數和帶請求頭信息的GET方法,支持https協議請求
     * @param url 請求url
     * @param headers 請求頭信息
     * @param params 請求參數
     * @param https 是否使用https協議
     */
    public static HttpClientResult doGet(String url, Map<String, String> headers, Map<String, String> params, boolean https){
        // 創建HttpGet
        HttpGet httpGet = null;
        // 創建httpResponse對象
        CloseableHttpResponse httpResponse = null;
        try {
            // 創建訪問的地址
            URIBuilder uriBuilder = new URIBuilder(url);
            if (params != null) {
                Set<Map.Entry<String, String>> entrySet = params.entrySet();
                for (Map.Entry<String, String> entry : entrySet) {
                    uriBuilder.setParameter(entry.getKey(), entry.getValue());
                }
            }
            // 創建HTTP對象
            httpGet = new HttpGet(uriBuilder.build());
            httpGet.setConfig(requestConfig);
            // 設置請求頭
            setHeader(headers, httpGet);
            // 使用不同的協議進行請求,返回自定義的響應對象
            if (https) {
                return getHttpClientResult(httpResponse, httpsClient, httpGet);
            } else {
                return getHttpClientResult(httpResponse, httpClient, httpGet);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 釋放資源
            if (httpGet != null) {
                httpGet.releaseConnection();
            }
            release(httpResponse);
        }

        return null;
    }

    /**
     * POST不帶參數,只支持http協議
     * @param url 請求url
     */
    public static HttpClientResult doPost(String url) {
        return doPost(url, Boolean.FALSE);
    }

    /**
     * 封裝不帶參數的post請求,支持https協議
     * @param url 請求url
     * @param https 是否是https協議
     */
    public static HttpClientResult doPost(String url, boolean https) {
        return doPost(url, null, (Map<String, String>)null, https);
    }

    /**
     * 帶參數的post請求,支持https協議
     * @param url 請求url
     * @param params 請求參數
     * @param https 是否是https協議
     */
    public static HttpClientResult doPost(String url, Map<String, String> params, boolean https) {
        return doPost(url, null, params, https);
    }

    /**
     * 帶參數和請求頭的POST請求,支持https
     *
     * @param url 請求url
     * @param headers 請求頭
     * @param params 請求參數,參數為K=V格式
     * @param https 是否https協議
     */
    public static HttpClientResult doPost(String url, Map<String, String> headers, Map<String, String> params, boolean https) {
        // 創建HTTP對象
        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(requestConfig);
        // 設置請求頭
        setHeader(headers, httpPost);
        // 封裝請求參數
        setParam(params, httpPost);
        // 創建httpResponse對象
        CloseableHttpResponse httpResponse = null;
        try {
            if (https) {
                return getHttpClientResult(httpResponse, httpsClient, httpPost);
            } else {
                return getHttpClientResult(httpResponse, httpClient, httpPost);
            }
        } finally {
            httpPost.releaseConnection();
            release(httpResponse);
        }
    }

    /**
     * 帶參數、帶請求頭的POST請求,支持https協議
     *
     * @param url 請求url
     * @param headers 請求頭
     * @param json 請求參數為json格式
     * @param https 是否使用https協議
     * @throws Exception
     */
    public static HttpClientResult doPost(String url, Map<String, String> headers, String json, boolean https) {
        // 創建HTTP對象
        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(requestConfig);
        // 設置請求頭
        setHeader(headers, httpPost);
        StringEntity stringEntity = new StringEntity(json, ENCODING);
        stringEntity.setContentEncoding(ENCODING);
        httpPost.setEntity(stringEntity);
        // 創建httpResponse對象
        CloseableHttpResponse httpResponse = null;
        try {
            if (https) {
                return getHttpClientResult(httpResponse, httpsClient, httpPost);
            } else {
                return getHttpClientResult(httpResponse, httpClient, httpPost);
            }
        } finally {
            httpPost.releaseConnection();
            release(httpResponse);
        }
    }


    /**
     * 發送put請求;不帶請求參數
     *
     * @param url 請求地址
     * @return
     * @throws Exception
     */
    public static HttpClientResult doPut(String url) {
        return doPut(url);
    }

    /**
     * 發送put請求;帶請求參數
     *
     * @param url 請求地址
     * @param params 參數集合
     * @return
     * @throws Exception
     */
    public static HttpClientResult doPut(String url, Map<String, String> params) {
        HttpPut httpPut = new HttpPut(url);
        httpPut.setConfig(requestConfig);
        setParam(params, httpPut);
        CloseableHttpResponse httpResponse = null;
        try {
            return getHttpClientResult(httpResponse, httpClient, httpPut);
        } finally {
            httpPut.releaseConnection();
            release(httpResponse);
        }
    }

    /**
     * 發送delete請求,不帶請求參數
     *
     * @param url 請求url
     * @return
     * @throws Exception
     */
    public static HttpClientResult doDelete(String url) {
        HttpDelete httpDelete = new HttpDelete(url);
        httpDelete.setConfig(requestConfig);
        CloseableHttpResponse httpResponse = null;
        try {
            return getHttpClientResult(httpResponse, httpClient, httpDelete);
        } finally {
            httpDelete.releaseConnection();
            release(httpResponse);
        }
    }

    /**
     * 發送delete請求,帶請求參數, 支持https協議
     *
     * @param url 請求url
     * @param params 請求參數
     * @param https 是否https
     * @return
     * @throws Exception
     */
    public static HttpClientResult doDelete(String url, Map<String, String> params, boolean https) {
        if (params == null) {
            params = new HashMap<String, String>();
        }
        params.put("_method", "delete");
        return doPost(url, params, https);
    }

    /**
     * 獲取cookie信息
     * @return 返回所有cookie集合
     */
    public static List<Cookie> getCookies() {
        return cookieStore.getCookies();
    }


    /**
     * 設置封裝請求頭
     *
     * @param params 頭信息
     * @param httpMethod 請求對象
     */
    public static void setHeader(Map<String, String> params, HttpRequestBase httpMethod) {
        // 封裝請求頭
        if (null != params && !params.isEmpty()) {
            Set<Map.Entry<String, String>> entrySet = params.entrySet();
            for (Map.Entry<String, String> entry : entrySet) {
                // 設置到請求頭到HttpRequestBase對象中
                httpMethod.setHeader(entry.getKey(), entry.getValue());
            }
        }
    }

    /**
     * 封裝請求參數
     *
     * @param params 請求參數
     * @param httpMethod 請求方法
     */
    public static void setParam(Map<String, String> params, HttpEntityEnclosingRequestBase httpMethod) {
        // 封裝請求參數
        if (null != params && !params.isEmpty()) {
            List<NameValuePair> nvps = new ArrayList<NameValuePair>();
            Set<Map.Entry<String, String>> entrySet = params.entrySet();
            for (Map.Entry<String, String> entry : entrySet) {
                nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
            }

            UrlEncodedFormEntity entity = null;
            try {
                entity = new UrlEncodedFormEntity(nvps, ENCODING);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            // 設置到請求的http對象中
            httpMethod.setEntity(entity);
        }
    }

    /**
     * 獲得響應結果
     *
     * @param httpResponse 響應對象
     * @param httpClient httpclient對象
     * @param httpMethod 請求方法
     * @return
     * @throws Exception
     */
    public static HttpClientResult getHttpClientResult(CloseableHttpResponse httpResponse, CloseableHttpClient httpClient, HttpRequestBase httpMethod) {
        try {
            // 執行請求
            httpResponse = httpClient.execute(httpMethod);
            // 獲取返回結果
            if (httpResponse != null && httpResponse.getStatusLine() != null) {
                String content = "";
                if (httpResponse.getEntity() != null) {
                    content = EntityUtils.toString(httpResponse.getEntity(), ENCODING);
                }
                return new HttpClientResult(httpResponse.getStatusLine().getStatusCode(), content);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new HttpClientResult(HttpStatus.SC_INTERNAL_SERVER_ERROR);
    }

    /**
     * 釋放資源
     *
     * @param httpResponse 響應對象
     */
    public static void release(CloseableHttpResponse httpResponse) {
        // 釋放資源
        if (httpResponse != null) {
            try {
                httpResponse.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

參考文章:
//www.cnblogs.com/zhc-hnust/p/12006923.html

Tags: