Java httpclent請求httpclentUtils工具類


第一種寫法:

 

import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.UnsupportedEncodingException;
import java.net.SocketTimeoutException;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.activation.MimetypesFileTypeMap;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.config.RequestConfig.Builder;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;

import lombok.extern.slf4j.Slf4j;
import net.dreamlu.common.entity.DownLoadFile;
import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;
import net.sf.json.util.PropertyFilter;


@Slf4j
public class HttpclientUtils implements IDictConst {
    private final static int    CONNECT_TIMEOUT            = 4000;        // 連接超時毫秒
    private final static int    SOCKET_TIMEOUT            = 30000;    // 傳輸超時毫秒
    private final static int    REQUESTCONNECT_TIMEOUT    = 3000;        // 獲取請求超時毫秒
    private final static String    ENCODE_CHARSET            = "utf-8";    // 響應報文解碼字符集

    static class RetryHandler implements HttpRequestRetryHandler {
        @Override
        public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
            if (executionCount >= 3) {
                // Do not retry if over max retry count
                return false;
            }
            if (exception instanceof InterruptedIOException) {
                // Timeout
                return false;
            }
            if (exception instanceof UnknownHostException) {
                // Unknown host
                return false;
            }
            if (exception instanceof ConnectTimeoutException) {
                // Connection refused
                return false;
            }
            if (exception instanceof SSLException) {
                // SSL handshake exception
                return false;
            }
            HttpClientContext clientContext = HttpClientContext.adapt(context);
            HttpRequest request = clientContext.getRequest();
            boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
            if (idempotent) {
                // Retry if the request is considered idempotent
                return true;
            }
            return false;
        }

    };

    public static CloseableHttpClient createSSLClientDefault(HttpHost proxy) {
        try {
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
                // 信任所有
                @Override
                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    return true;
                }
            }).build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
            HttpRequestRetryHandler retryHandler = new RetryHandler();
            Builder buider = RequestConfig.custom().setConnectionRequestTimeout(REQUESTCONNECT_TIMEOUT).setConnectTimeout(CONNECT_TIMEOUT).setSocketTimeout(SOCKET_TIMEOUT);
            if (null != proxy) {
                buider.setProxy(proxy);
            }
            RequestConfig requestConfig = buider.build();
            HttpClients.custom().setSSLSocketFactory(sslsf).setDefaultRequestConfig(requestConfig).setRetryHandler(retryHandler).build();
        } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
            log.error(e.getMessage(), e);
        }
        return HttpClients.createDefault();
    }

    public static String buildMap(Map<String, Object> map) {
        StringBuffer sb = new StringBuffer();
        if (map != null && map.size() > 0) {
            for (String key : map.keySet()) {
                sb.append(key + "=");
                if (null == map.get(key)) {
                    sb.append("&");
                } else {
                    String value = String.valueOf(map.get(key));
                    try {
                        value = URLEncoder.encode(value, "UTF-8");
                    } catch (UnsupportedEncodingException e) {
                        log.error(e.getMessage(), e);
                    }
                    sb.append(value + "&");
                }
            }
        }
        return sb.toString();
    }

    /**
     * 發送HTTP_GET請求
     *
     * @see 1)該方法會自動關閉連接,釋放資源
     * @see 2)方法內設置了連接和讀取超時時間,單位為毫秒,超時或發生其它異常時方法會自動返回"通信失敗"字符串
     * @see 3)請求參數含中文時,經測試可直接傳入中文,HttpClient會自動編碼發給Server,應用時應根據實際效果決 定傳入前是否轉碼
     * @see 4)該方法會自動獲取到響應消息頭中[Content-Type:text/html; charset=GBK]的charset值作為響應報文的 解碼字符集
     * @see 5)若響應消息頭中無Content-Type屬性,則會使用HttpClient內部默認的ISO-8859-1作為響應報文的解碼字符 集
     * @param reqURL 請求地址(含參數)
     * @return 遠程主機響應正文 HttpHost proxy = new HttpHost("192.168.15.4", 3128);
     */
    public static JSONObject sendGetRequest(String reqURL, Map<String, Object> map, HttpHost proxy) {
        String param = buildMap(map);
        if (null != param) {
            reqURL += "?" + param;
        }
        JSONObject respContent = new JSONObject(); // 響應內容
//         reqURL = URLDecoder.decode(reqURL, ENCODE_CHARSET);
        HttpGet httpget = new HttpGet(reqURL);
        httpget.setHeader("Connection", "close");
        CloseableHttpResponse response = null;
        try {
            response = createSSLClientDefault(proxy).execute(httpget, HttpClientContext.create()); // 執行GET請求
            HttpEntity entity = response.getEntity(); // 獲取響應實體
            if (null != entity) {
                Charset respCharset = Charset.forName(ENCODE_CHARSET);
                respContent = JSONObject.fromObject(EntityUtils.toString(entity, respCharset), getJsonConfig());
                log.info("發送get請求返回結果:{}", respContent);
                EntityUtils.consume(entity);
            } else {
                log.error("發送get請求返回錯誤:{}", response);
            }
        } catch (ConnectTimeoutException cte) {
            log.error("請求通信[" + reqURL + "]時連接超時,堆棧軌跡如下", cte);
            respContent.put(CODE, -1000);
            respContent.put(MSG, cte.getMessage());
        } catch (SocketTimeoutException ste) {
            log.error("請求通信[" + reqURL + "]時讀取超時,堆棧軌跡如下", ste);
            respContent.put(CODE, -1000);
            respContent.put(MSG, ste.getMessage());
        } catch (ClientProtocolException cpe) {
            log.error("請求通信[" + reqURL + "]時協議異常,堆棧軌跡如下", cpe);
            respContent.put(CODE, -1000);
            respContent.put(MSG, cpe.getMessage());
        } catch (ParseException pe) {
            log.error("請求通信[" + reqURL + "]時解析異常,堆棧軌跡如下", pe);
            respContent.put(CODE, -1000);
            respContent.put(MSG, pe.getMessage());
        } catch (IOException ioe) {
            log.error("請求通信[" + reqURL + "]時網絡異常,堆棧軌跡如下", ioe);
            respContent.put(CODE, -1000);
            respContent.put(MSG, ioe.getMessage());
        } catch (Exception e) {
            log.error("請求通信[" + reqURL + "]時偶遇異常,堆棧軌跡如下", e);
            respContent.put(CODE, -1000);
            respContent.put(MSG, e.getMessage());
        } finally {
            try {
                if (response != null)
                    response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (httpget != null) {
                httpget.releaseConnection();
            }
        }
        return respContent;
    }

    /**
     * 將null值的字段去掉
     * 
     * @return
     */
    private static JsonConfig getJsonConfig() {
        JsonConfig jsonConfig = new JsonConfig();
        jsonConfig.setJsonPropertyFilter(new PropertyFilter() {
            @Override
            public boolean apply(Object arg0, String arg1, Object arg2) {
                return StringUtils.equals("null", String.valueOf(arg2));
            }
        });
        return jsonConfig;
    }

    /**
     * 發送HTTP_POST請求 type: 默認是表單請求,
     * 
     * @see 1)該方法允許自定義任何格式和內容的HTTP請求報文體
     * @see 2)該方法會自動關閉連接,釋放資源
     * @see 3)方法內設置了連接和讀取超時時間,單位為毫秒,超時或發生其它異常時方法會自動返回"通信失敗"字符串
     * @see 4)請求參數含中文等特殊字符時,可直接傳入本方法,並指明其編碼字符集encodeCharset參數,方法內部會自 動對其轉碼
     * @see 5)該方法在解碼響應報文時所采用的編碼,取自響應消息頭中的[Content-Type:text/html; charset=GBK]的 charset值
     * @see 6)若響應消息頭中未指定Content-Type屬性,則會使用HttpClient內部默認的ISO-8859-1
     * @param reqURL 請求地址
     * @param param 請求參數,若有多個參數則應拼接為param11=value11&22=value22&33=value33的形式
     * @param type 編碼字符集,編碼請求數據時用之,此參數為必填項(不能為""或null)
     * @return 遠程主機響應正文
     */
    public static JSONObject sendPostRequest(String reqURL, Map<String, Object> map, String type, HttpHost proxy) {
        JSONObject respContent = new JSONObject();
        // 設置請求和傳輸超時時間
        HttpPost httpPost = new HttpPost(reqURL);
        httpPost.setHeader("Connection", "close");
        // 這就有可能會導致服務端接收不到POST過去的參數,比如運行在Tomcat6.0.36中的Servlet,所以我們手工指定CONTENT_TYPE頭消息
        if (type != null && type.length() > 0) {
            httpPost.setHeader(HTTP.CONTENT_TYPE, "application/json; charset=" + ENCODE_CHARSET);
        } else {
            httpPost.setHeader(HTTP.CONTENT_TYPE, "application/x-www-form-urlencoded; charset=" + ENCODE_CHARSET);
        }
        CloseableHttpResponse response = null;
        try {
            // 判斷map不為空
            if (map != null) {
                // 聲明存放參數的List集合
                List<NameValuePair> params = new ArrayList<NameValuePair>();
                // 遍歷map,設置參數到list中
                for (Map.Entry<String, Object> entry : map.entrySet()) {
                    if (null != entry.getValue()) {
                        params.add(new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue())));
                    }
                }
                // 創建form表單對象
                UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(params, ENCODE_CHARSET);
                formEntity.setContentType("Content-Type:application/json");
                // 把表單對象設置到httpPost中
                httpPost.setEntity(formEntity);
            }
            // reqURL = URLDecoder.decode(reqURL, ENCODE_CHARSET);
            response = createSSLClientDefault(proxy).execute(httpPost, HttpClientContext.create());
            HttpEntity entity = response.getEntity();
            if (null != entity) {
                respContent = JSONObject.fromObject(EntityUtils.toString(entity, Charset.forName(ENCODE_CHARSET)), getJsonConfig());
                log.info("發送post請求返回結果:{}", respContent);
                EntityUtils.consume(entity);
            } else {
                log.error("發送post請求返回錯誤:{}", response);
            }
        } catch (ConnectTimeoutException cte) {
            log.error("請求通信[" + reqURL + "]時連接超時,堆棧軌跡如下", cte);
            respContent.put(CODE, -1000);
            respContent.put(MSG, cte.getMessage());
        } catch (SocketTimeoutException ste) {
            log.error("請求通信[" + reqURL + "]時讀取超時,堆棧軌跡如下", ste);
            respContent.put(CODE, -1000);
            respContent.put(MSG, ste.getMessage());
        } catch (ClientProtocolException cpe) {
            log.error("請求通信[" + reqURL + "]時協議異常,堆棧軌跡如下", cpe);
            respContent.put(CODE, -1000);
            respContent.put(MSG, cpe.getMessage());
        } catch (ParseException pe) {
            log.error("請求通信[" + reqURL + "]時解析異常,堆棧軌跡如下", pe);
            respContent.put(CODE, -1000);
            respContent.put(MSG, pe.getMessage());
        } catch (IOException ioe) {
            log.error("請求通信[" + reqURL + "]時網絡異常,堆棧軌跡如下", ioe);
            respContent.put(CODE, -1000);
            respContent.put(MSG, ioe.getMessage());
        } catch (Exception e) {
            log.error("請求通信[" + reqURL + "]時偶遇異常,堆棧軌跡如下", e);
            respContent.put(CODE, -1000);
            respContent.put(MSG, e.getMessage());
        } finally {
            try {
                if (response != null)
                    response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (httpPost != null) {
                httpPost.releaseConnection();
            }
        }
        return respContent;
    }

    public static String getContentType(String filename) {
        String contentType = null;
        try {
            contentType = new MimetypesFileTypeMap().getContentType(filename);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return contentType;
    }

    /**
     * 上傳文件功能
     * 
     * @param reqURL
     * @param b
     * @param filename
     * @param map
     * @param type
     * @return
     */
    public static JSONObject sendPostFileRequest(String reqURL, byte[] b, String filename, Map<String, Object> map, HttpHost proxy) {
        JSONObject respContent = new JSONObject();
        HttpPost httpPost = new HttpPost(reqURL);
        httpPost.setHeader("Connection", "close");
        CloseableHttpResponse response = null;
        try {
            // 判斷map不為空
            if (map != null) {
                MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
                multipartEntityBuilder.setCharset(Charset.forName(ENCODE_CHARSET));
                multipartEntityBuilder.addBinaryBody("file", b, ContentType.create(getContentType(filename)), filename);
                for (Map.Entry<String, Object> entry : map.entrySet()) {
                    multipartEntityBuilder.addTextBody(entry.getKey(), String.valueOf(entry.getValue()));
                }
                HttpEntity httpEntity = multipartEntityBuilder.build();
                httpPost.setEntity(httpEntity);
            }
            // reqURL = URLDecoder.decode(reqURL, ENCODE_CHARSET);
            response = createSSLClientDefault(proxy).execute(httpPost, HttpClientContext.create());
            HttpEntity entity = response.getEntity();
            if (null != entity) {
                respContent = JSONObject.fromObject(EntityUtils.toString(entity, Charset.forName(ENCODE_CHARSET)), getJsonConfig());
                log.info("發送post請求返回結果:{}", respContent);
                EntityUtils.consume(entity);
            } else {
                log.error("發送post請求返回錯誤:{}", response);
            }
        } catch (ConnectTimeoutException cte) {
            log.error("請求通信[" + reqURL + "]時連接超時,堆棧軌跡如下", cte);
            respContent.put(CODE, -1000);
            respContent.put(MSG, cte.getMessage());
        } catch (SocketTimeoutException ste) {
            log.error("請求通信[" + reqURL + "]時讀取超時,堆棧軌跡如下", ste);
            respContent.put(CODE, -1000);
            respContent.put(MSG, ste.getMessage());
        } catch (ClientProtocolException cpe) {
            log.error("請求通信[" + reqURL + "]時協議異常,堆棧軌跡如下", cpe);
            respContent.put(CODE, -1000);
            respContent.put(MSG, cpe.getMessage());
        } catch (ParseException pe) {
            log.error("請求通信[" + reqURL + "]時解析異常,堆棧軌跡如下", pe);
            respContent.put(CODE, -1000);
            respContent.put(MSG, pe.getMessage());
        } catch (IOException ioe) {
            log.error("請求通信[" + reqURL + "]時網絡異常,堆棧軌跡如下", ioe);
            respContent.put(CODE, -1000);
            respContent.put(MSG, ioe.getMessage());
        } catch (Exception e) {
            log.error("請求通信[" + reqURL + "]時偶遇異常,堆棧軌跡如下", e);
            respContent.put(CODE, -1000);
            respContent.put(MSG, e.getMessage());
        } finally {
            try {
                if (response != null)
                    response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (httpPost != null) {
                httpPost.releaseConnection();
            }
        }
        return respContent;
    }

    /**
     * 上傳文件功能
     * 
     * @param reqURL
     * @param b
     * @param filename
     * @param map
     * @param type
     * @return
     */
    public static DownLoadFile downFileRequest(String reqURL, Map<String, Object> map, HttpHost proxy) {
        DownLoadFile respContent = new DownLoadFile();
        HttpPost httpPost = new HttpPost(reqURL);
        httpPost.setHeader("Connection", "close");
        CloseableHttpResponse response = null;
        try {
            // 判斷map不為空
            if (map != null) {
                // 聲明存放參數的List集合
                List<NameValuePair> params = new ArrayList<NameValuePair>();
                // 遍歷map,設置參數到list中
                for (Map.Entry<String, Object> entry : map.entrySet()) {
                    if (null != entry.getValue()) {
                        params.add(new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue())));
                    }
                }
                // 創建form表單對象
                UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(params, ENCODE_CHARSET);
                formEntity.setContentType("Content-Type:application/json");
                // 把表單對象設置到httpPost中
                httpPost.setEntity(formEntity);
            }
            // reqURL = URLDecoder.decode(reqURL, ENCODE_CHARSET);
            response = createSSLClientDefault(proxy).execute(httpPost, HttpClientContext.create());
            int code = response.getStatusLine().getStatusCode();
            if (code == 302) {
                Header header = response.getFirstHeader("location"); // 跳轉的目標地址是在 HTTP-HEAD上
                String newuri = header.getValue(); // 這就是跳轉后的地址,再向這個地址發出新申請
                httpPost = new HttpPost(newuri);
                httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
                response = createSSLClientDefault(proxy).execute(httpPost, HttpClientContext.create());
                code = response.getStatusLine().getStatusCode();
                if (code == 200) {
                    respContent.setFileName(StringUtils.substringAfterLast(newuri, "/"));
                    HttpEntity entity = response.getEntity();
                    if (null != entity) {
                        respContent.setFileContent(EntityUtils.toByteArray(entity));
                        EntityUtils.consume(entity);
                    } else {
                        log.error("發送post請求返回錯誤:{}", response);
                    }
                }
            } else if (code == 200) {
                Header header = response.getFirstHeader("location"); // 跳轉的目標地址是在 HTTP-HEAD上
                String newuri = header.getValue();
                HttpEntity entity = response.getEntity();
                if (null != entity) {
                    respContent.setFileName(StringUtils.substringAfterLast(newuri, "/"));
                    respContent.setFileContent(EntityUtils.toByteArray(entity));
                    EntityUtils.consume(entity);
                } else {
                    log.error("發送post請求返回錯誤:{}", response);
                }
            }
        } catch (ConnectTimeoutException cte) {
            log.error("請求通信[" + reqURL + "]時連接超時,堆棧軌跡如下", cte);
        } catch (SocketTimeoutException ste) {
            log.error("請求通信[" + reqURL + "]時讀取超時,堆棧軌跡如下", ste);
        } catch (ClientProtocolException cpe) {
            log.error("請求通信[" + reqURL + "]時協議異常,堆棧軌跡如下", cpe);
        } catch (ParseException pe) {
            log.error("請求通信[" + reqURL + "]時解析異常,堆棧軌跡如下", pe);
        } catch (IOException ioe) {
            log.error("請求通信[" + reqURL + "]時網絡異常,堆棧軌跡如下", ioe);
        } catch (Exception e) {
            log.error("請求通信[" + reqURL + "]時偶遇異常,堆棧軌跡如下", e);
        } finally {
            try {
                if (response != null)
                    response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (httpPost != null) {
                httpPost.releaseConnection();
            }
        }
        return respContent;
    }
}

第二種寫法;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.NoHttpResponseException;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
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.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.pool.PoolStats;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.apache.poi.util.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sinoeyes.common.IDictConst;
import com.sinoeyes.web.entity.achieve.DownLoadFile;

import net.sf.json.JSONObject;

public class HttpClientUtil implements IDictConst {
	private static Logger								logger					= LoggerFactory.getLogger(HttpClientUtil.class);
	private final static int							CONNECT_TIMEOUT			= 4000;											// 連接超時毫秒
	private final static int							SOCKET_TIMEOUT			= 30000;										// 傳輸超時毫秒
	private final static int							SOCKET_TIMEOUT_DELAY	= 180000;										// 最長傳輸超時毫秒
	private final static int							REQUESTCONNECT_TIMEOUT	= 3000;											// 獲取請求超時毫秒
	private final static int							CONNECT_TOTAL			= 800;											// 最大連接數
	private final static int							CONNECT_ROUTE			= 800;											// 每個路由基礎的連接數
	private final static String							ENCODE_CHARSET			= "utf-8";										// 響應報文解碼字符集
	private final static String							RESP_CONTENT			= "通信失敗";
	public static PoolingHttpClientConnectionManager	connManager				= null;
	private static CloseableHttpClient					httpClient				= null;
	static {
		ConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory();
		LayeredConnectionSocketFactory sslsf = createSSLConnSocketFactory();
		Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory> create().register("http", plainsf).register("https", sslsf).build();
		connManager = new PoolingHttpClientConnectionManager(registry);
		// 將最大連接數增加到200
		connManager.setMaxTotal(CONNECT_TOTAL);
		// 將每個路由基礎的連接增加到20
		connManager.setDefaultMaxPerRoute(CONNECT_ROUTE);
		// 可用空閑連接過期時間,重用空閑連接時會先檢查是否空閑時間超過這個時間,如果超過,釋放socket重新建立
		connManager.setValidateAfterInactivity(30000);
		// 設置socket超時時間
		SocketConfig socketConfig = SocketConfig.custom().setSoTimeout(SOCKET_TIMEOUT).build();
		connManager.setDefaultSocketConfig(socketConfig);

		RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(REQUESTCONNECT_TIMEOUT).setConnectTimeout(CONNECT_TIMEOUT).setSocketTimeout(SOCKET_TIMEOUT)
				.build();
		HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() {
			@Override
			public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
				if (executionCount >= 3) {// 如果已經重試了3次,就放棄
					return false;
				}
				if (exception instanceof NoHttpResponseException) {// 如果服務器丟掉了連接,那么就重試
					return true;
				}
				if (exception instanceof SSLHandshakeException) {// 不要重試SSL握手異常
					return false;
				}
				if (exception instanceof InterruptedIOException) {// 超時
					return true;
				}
				if (exception instanceof UnknownHostException) {// 目標服務器不可達
					return false;
				}
				if (exception instanceof ConnectTimeoutException) {// 連接被拒絕
					return false;
				}
				if (exception instanceof SSLException) {// ssl握手異常
					return false;
				}
				HttpClientContext clientContext = HttpClientContext.adapt(context);
				HttpRequest request = clientContext.getRequest();
				// 如果請求是冪等的,就再次嘗試
				if (!(request instanceof HttpEntityEnclosingRequest)) {
					return true;
				}
				return false;
			}
		};
		httpClient = HttpClients.custom().setConnectionManager(connManager).setDefaultRequestConfig(requestConfig).setRetryHandler(httpRequestRetryHandler).build();
		if (connManager != null && connManager.getTotalStats() != null) {
			logger.info("now client pool " + connManager.getTotalStats().toString());
		}
	}

	/**
	 * 發送HTTP_GET請求
	 *
	 * @see 1)該方法會自動關閉連接,釋放資源
	 * @see 2)方法內設置了連接和讀取超時時間,單位為毫秒,超時或發生其它異常時方法會自動返回"通信失敗"字符串
	 * @see 3)請求參數含中文時,經測試可直接傳入中文,HttpClient會自動編碼發給Server,應用時應根據實際效果決 定傳入前是否轉碼
	 * @see 4)該方法會自動獲取到響應消息頭中[Content-Type:text/html; charset=GBK]的charset值作為響應報文的 解碼字符集
	 * @see 5)若響應消息頭中無Content-Type屬性,則會使用HttpClient內部默認的ISO-8859-1作為響應報文的解碼字符 集
	 * @param reqURL 請求地址(含參數)
	 * @return 遠程主機響應正文
	 */
	public static String sendGetRequest(String reqURL, String param) {
		if (null != param) {
			reqURL += "?" + param;
		}
		String respContent = RESP_CONTENT; // 響應內容
// reqURL = URLDecoder.decode(reqURL, ENCODE_CHARSET);
		HttpGet httpget = new HttpGet(reqURL);
		CloseableHttpResponse response = null;
		try {
			response = httpClient.execute(httpget, HttpClientContext.create()); // 執行GET請求
			HttpEntity entity = response.getEntity(); // 獲取響應實體
			if (null != entity) {
				Charset respCharset = ContentType.getOrDefault(entity).getCharset();
				respContent = EntityUtils.toString(entity, respCharset);
				EntityUtils.consume(entity);
			}
		} catch (ConnectTimeoutException cte) {
			logger.error("請求通信[" + reqURL + "]時連接超時,堆棧軌跡如下", cte);
		} catch (SocketTimeoutException ste) {
			logger.error("請求通信[" + reqURL + "]時讀取超時,堆棧軌跡如下", ste);
		} catch (ClientProtocolException cpe) {
// 該異常通常是協議錯誤導致:比如構造HttpGet對象時傳入協議不對(將'http'寫成'htp')or響應內容不符合HTTP協議要求等
			logger.error("請求通信[" + reqURL + "]時協議異常,堆棧軌跡如下", cpe);
		} catch (ParseException pe) {
			logger.error("請求通信[" + reqURL + "]時解析異常,堆棧軌跡如下", pe);
		} catch (IOException ioe) {
// 該異常通常是網絡原因引起的,如HTTP服務器未啟動等
			logger.error("請求通信[" + reqURL + "]時網絡異常,堆棧軌跡如下", ioe);
		} catch (Exception e) {
			logger.error("請求通信[" + reqURL + "]時偶遇異常,堆棧軌跡如下", e);
		} finally {
			try {
				if (response != null)
					response.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			if (httpget != null) {
				httpget.releaseConnection();
			}
		}
		return respContent;
	}

	public static String sendPostRequest(String reqURL, String param) throws IOException {
		return sendPostRequest(reqURL, param, "");
	}

	/**
	 * 發送HTTP_POST請求 type: 默認是表單請求,
	 * 
	 * @see 1)該方法允許自定義任何格式和內容的HTTP請求報文體
	 * @see 2)該方法會自動關閉連接,釋放資源
	 * @see 3)方法內設置了連接和讀取超時時間,單位為毫秒,超時或發生其它異常時方法會自動返回"通信失敗"字符串
	 * @see 4)請求參數含中文等特殊字符時,可直接傳入本方法,並指明其編碼字符集encodeCharset參數,方法內部會自 動對其轉碼
	 * @see 5)該方法在解碼響應報文時所采用的編碼,取自響應消息頭中的[Content-Type:text/html; charset=GBK]的 charset值
	 * @see 6)若響應消息頭中未指定Content-Type屬性,則會使用HttpClient內部默認的ISO-8859-1
	 * @param reqURL 請求地址
	 * @param param 請求參數,若有多個參數則應拼接為param11=value11&22=value22&33=value33的形式
	 * @param type 編碼字符集,編碼請求數據時用之,此參數為必填項(不能為""或null)
	 * @return 遠程主機響應正文
	 */
	public static String sendPostRequest(String reqURL, String param, String type) {
		String result = RESP_CONTENT;
		// 設置請求和傳輸超時時間
		HttpPost httpPost = new HttpPost(reqURL);
		// 這就有可能會導致服務端接收不到POST過去的參數,比如運行在Tomcat6.0.36中的Servlet,所以我們手工指定CONTENT_TYPE頭消息
		if (type != null && type.length() > 0) {
			httpPost.setHeader(HTTP.CONTENT_TYPE, "application/json; charset=" + ENCODE_CHARSET);
		} else {
			httpPost.setHeader(HTTP.CONTENT_TYPE, "application/x-www-form-urlencoded; charset=" + ENCODE_CHARSET);
		}
		CloseableHttpResponse response = null;
		try {
			if (param != null) {
				StringEntity entity = new StringEntity(param, ENCODE_CHARSET);
				httpPost.setEntity(entity);
			}
			logger.info("開始執行請求:" + reqURL);
			// reqURL = URLDecoder.decode(reqURL, ENCODE_CHARSET);
			response = httpClient.execute(httpPost, HttpClientContext.create());
			HttpEntity entity = response.getEntity();
			if (null != entity) {
				result = EntityUtils.toString(entity, ContentType.getOrDefault(entity).getCharset());
				logger.info("執行請求完畢:" + result);
				EntityUtils.consume(entity);
			}
		} catch (ConnectTimeoutException cte) {
			logger.error("請求通信[" + reqURL + "]時連接超時,堆棧軌跡如下", cte);
		} catch (SocketTimeoutException ste) {
			logger.error("請求通信[" + reqURL + "]時讀取超時,堆棧軌跡如下", ste);
		} catch (ClientProtocolException cpe) {
			logger.error("請求通信[" + reqURL + "]時協議異常,堆棧軌跡如下", cpe);
		} catch (ParseException pe) {
			logger.error("請求通信[" + reqURL + "]時解析異常,堆棧軌跡如下", pe);
		} catch (IOException ioe) {
			logger.error("請求通信[" + reqURL + "]時網絡異常,堆棧軌跡如下", ioe);
		} catch (Exception e) {
			logger.error("請求通信[" + reqURL + "]時偶遇異常,堆棧軌跡如下", e);
		} finally {
			try {
				if (response != null)
					response.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			if (httpPost != null) {
				httpPost.releaseConnection();
			}
		}
		return result;
	}

	/**
	 * 上傳文件
	 * 
	 * @param url
	 * @param bodyBytes
	 * @param boundary
	 * @return
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	public static JSONObject uploadFile(String url, byte[] bodyBytes, String boundary) throws ClientProtocolException, IOException {
		if (null != connManager) {
			connManager.closeExpiredConnections();
			connManager.closeIdleConnections(180L, TimeUnit.SECONDS);
		}
		JSONObject result = new JSONObject();
		HttpPost post = new HttpPost(url);
		post.setHeader(HttpHeaders.CONNECTION, "close");
		RequestConfig requestConfig = doProxy(true, false);
		post.setConfig(requestConfig);
		post.addHeader("Content-Type", "multipart/form-data; boundary=" + boundary);
		post.setEntity(new ByteArrayEntity(bodyBytes));
		CloseableHttpResponse response = null;
		try {
			response = httpClient.execute(post);
			int code = response.getStatusLine().getStatusCode();
			if (code == 200) {
				HttpEntity entity = response.getEntity();
				byte[] entityByte = EntityUtils.toByteArray(entity);
				byte[] entityStr = AesUtil.decrypt(entityByte);
				EntityUtils.consume(entity);
				if (null != entityStr && entityStr.length > 0) {// 正常解密
					result = JSONObject.fromObject(new String(entityStr, ENCODE_CHARSET));
				} else {
					// 解密失敗
					String s = new String(entityByte, ENCODE_CHARSET);
					if (StringUtils.isNotBlank(s) && StringUtils.startsWith(s, "{")) {
						result = JSONObject.fromObject(s);
					} else {
						result.put(ERROR_CODE, ERROR_EXCEPTION);
						result.put(ERROR_MESSAGE, s);
					}
				}
				return result;
			} else {
				result.put(ERROR_CODE, code);
				result.put(ERROR_MESSAGE, "請求失敗!");
			}
		} catch (Exception e) {
			e.printStackTrace();
			result.put(ERROR_CODE, ERROR_EXCEPTION);
			result.put(ERROR_MESSAGE, e.getMessage());
		} finally {
			if (response != null) {
				EntityUtils.consumeQuietly(response.getEntity());
			}
			if (post != null) {
				post.releaseConnection();
			}
		}
		return result;
	}

	/**
	 * 正常httpclent請求
	 * 
	 * @param reqURL
	 * @param json
	 * @param isProxy
	 * @return
	 */
	public static JSONObject sendPostRequest(String reqURL, JSONObject json, boolean isProxy) {
		return sendPostRequestCommon(reqURL, json, isProxy, false);
	}

	/**
	 * 加長傳輸時間httpclent請求
	 * 
	 * @param reqURL
	 * @param json
	 * @param isProxy
	 * @return
	 */
	public static JSONObject sendPostRequestSlow(String reqURL, JSONObject json, boolean isProxy) {
		return sendPostRequestCommon(reqURL, json, isProxy, true);
	}

	/**
	 * 下載文件功能
	 * 
	 * @param url
	 * @param json
	 * @return
	 */
	public static DownLoadFile downLoadFile(String url, String json) {
		if (null != connManager) {
			connManager.closeExpiredConnections();
			connManager.closeIdleConnections(180L, TimeUnit.SECONDS);
		}
		byte[] encryptByte = AesUtil.encrypt(json);
		HttpPost post = new HttpPost(url);
		RequestConfig requestConfig = doProxy(true, false);
		post.setHeader(HttpHeaders.CONNECTION, "close");
		post.setConfig(requestConfig);
		post.setEntity(new ByteArrayEntity(encryptByte));
		CloseableHttpResponse response = null;
		DownLoadFile file = new DownLoadFile();
		try {
			response = httpClient.execute(post);
			if (response.getStatusLine().getStatusCode() == 200) {
				HttpEntity entity = response.getEntity();
				if (entity.getContentType().getValue().contains("application/octet-stream")) {
					byte[] toByte = IOUtils.toByteArray(response.getEntity().getContent());
					byte[] derByte = AesUtil.decrypt(toByte);
					file.setError_code(0);
					file.setError_message("ok");
					file.setBytes(derByte);
					file.setFileName(getFileName(response));
					file.setContentType(entity.getContentType().getValue());
					return file;
				} else if (response.getEntity().getContentType().getValue().contains("text/plain")) {
					byte[] entityByte = EntityUtils.toByteArray(response.getEntity());
					byte[] entityStr = AesUtil.decrypt(entityByte);
					JSONObject jsonResult;
					if (null != entityStr && entityStr.length > 0) {
						jsonResult = JSONObject.fromObject(new String(entityStr, ENCODE_CHARSET));
					} else {
						String s = new String(entityByte, ENCODE_CHARSET);
						logger.info("下載文件返回的字符串是:{}", s);
						jsonResult = JSONObject.fromObject(s);
					}
					file.setError_code(jsonResult.getInt(ERROR_CODE));
					file.setError_message(jsonResult.getString(ERROR_MESSAGE));
					return file;
				}
			}
		} catch (Exception e) {
			file.setError_code(ERROR_EXCEPTION);
			file.setError_message(e.getMessage());
			logger.error(e.getMessage(), e);
		} finally {
			if (response != null) {
				EntityUtils.consumeQuietly(response.getEntity());
			}
			if (post != null) {
				post.releaseConnection();
			}
		}
		return file;
	}

	/**
	 * 獲取Header標頭中的filename,文件名稱
	 *
	 * @param response
	 * @return
	 */
	public static String getFileName(HttpResponse response) {
		Header contentHeader = response.getFirstHeader("Content-Disposition");
		String filename = null;
		if (contentHeader != null) {
			HeaderElement[] values = contentHeader.getElements();
			if (values.length == 1) {
				NameValuePair param = values[0].getParameterByName("filename");
				if (param != null) {
					try {
						filename = new String(param.getValue().getBytes("iso-8859-1"), ENCODE_CHARSET);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		}
		return filename;
	}

	/**
	 * 代理設置
	 * 
	 * @param isProxy
	 * @return
	 */
	private static RequestConfig doProxy(boolean isProxy, boolean delay) {
		RequestConfig.Builder configBuilder = RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT).setSocketTimeout(SOCKET_TIMEOUT);
		if (delay) {
			configBuilder.setSocketTimeout(SOCKET_TIMEOUT_DELAY);
		}
		if (CloudBootStrapUtils.PROXY_START && isProxy) {
			HttpHost proxy = new HttpHost(CloudBootStrapUtils.PROXY_ADDRESS, CloudBootStrapUtils.PROXY_PORT);
			configBuilder.setProxy(proxy);
		}
		return configBuilder.build();
	}

	/**
	 * 發送post請求
	 * 
	 * @param reqURL
	 * @param json
	 * @param isProxy
	 * @return
	 */
	private static JSONObject sendPostRequestCommon(String reqURL, JSONObject json, boolean isProxy, boolean delay) {
		if (null != connManager) {
			connManager.closeExpiredConnections();
			connManager.closeIdleConnections(180L, TimeUnit.SECONDS);
		}
		PoolStats poolStats;
		if (connManager != null && (poolStats = connManager.getTotalStats()) != null) {
			if (poolStats.getLeased() > 100 || poolStats.getPending() > 1) {
				logger.info("now client pool {}", poolStats);
			}
		}
		JSONObject jsonResult = new JSONObject();
		// 創建HTTP請求
		HttpPost post = new HttpPost(reqURL);
		post.setHeader(HttpHeaders.CONNECTION, "close");
		// 參數AEC加密
		byte[] encryptByte = AesUtil.encrypt(json.toString());
		if (isProxy) {
			RequestConfig requestConfig = doProxy(isProxy, delay);
			if (null != requestConfig) {
				post.setConfig(requestConfig);
			}
		}
		// 設置訪問字節型
		post.setEntity(new ByteArrayEntity(encryptByte));
		CloseableHttpResponse response = null;
		try {
			response = httpClient.execute(post);
			HttpEntity entity = response.getEntity();
			if (response.getStatusLine().getStatusCode() == 200 && null != entity) {
				byte[] entityByte = EntityUtils.toByteArray(entity);
				byte[] entityStr = AesUtil.decrypt(entityByte);
				EntityUtils.consume(entity);
				if (null != entityStr && entityStr.length > 0) {// 正常解密
					jsonResult = JSONObject.fromObject(new String(entityStr, ENCODE_CHARSET));
				} else {
					// 解密失敗
					String s = new String(entityByte, ENCODE_CHARSET);
					if (StringUtils.isNotBlank(s) && StringUtils.startsWith(s, "{")) {
						jsonResult = JSONObject.fromObject(s);
					} else {
						jsonResult.put(ERROR_CODE, ERROR_EXCEPTION);
						jsonResult.put(ERROR_MESSAGE, s);
					}
				}
				return jsonResult;
			}
			jsonResult.put(ERROR_CODE, response.getStatusLine().getStatusCode());
			jsonResult.put(ERROR_MESSAGE, response.getStatusLine().toString());
		} catch (Exception e) {
			jsonResult.put(ERROR_CODE, ERROR_EXCEPTION);
			jsonResult.put(ERROR_MESSAGE, e.getMessage());
		} finally {
			if (response != null) {
				EntityUtils.consumeQuietly(response.getEntity());
			}
			if (post != null) {
				post.releaseConnection();
			}
		}
		return jsonResult;
	}

	/**
	 * SSL的socket工廠創建
	 */
	private static SSLConnectionSocketFactory createSSLConnSocketFactory() {
		SSLConnectionSocketFactory sslsf = null;
		// 創建TrustManager() 用於解決javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
		X509TrustManager trustManager = new X509TrustManager() {
			@Override
			public X509Certificate[] getAcceptedIssuers() {
				return null;
			}

			@Override
			public void checkClientTrusted(X509Certificate[] arg0, String authType) throws CertificateException {
			}

			@Override
			public void checkServerTrusted(X509Certificate[] arg0, String authType) throws CertificateException {
			}
		};
		SSLContext sslContext;
		try {
			sslContext = SSLContext.getInstance(SSLConnectionSocketFactory.TLS);
			sslContext.init(null, new TrustManager[] { (TrustManager) trustManager }, null);
			// 創建SSLSocketFactory , // 不校驗域名 ,取代以前驗證規則
			sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		}
		return sslsf;
	}

	/**
	 * httpclent連接池的狀態
	 * 
	 * @return
	 */
	public static Map<HttpRoute, PoolStats> getConnManagerStats() {
		if (connManager != null) {
			Set<HttpRoute> routeSet = connManager.getRoutes();
			if (routeSet != null && !routeSet.isEmpty()) {
				Map<HttpRoute, PoolStats> routeStatsMap = new HashMap<HttpRoute, PoolStats>();
				for (HttpRoute route : routeSet) {
					PoolStats stats = connManager.getStats(route);
					routeStatsMap.put(route, stats);
				}
				return routeStatsMap;
			}
		}
		return null;
	}

	/**
	 * 獲取當前連接池的狀態
	 * 
	 * @return
	 */
	public static PoolStats getConnManagerTotalStats() {
		if (connManager != null) {
			return connManager.getTotalStats();
		}
		return null;
	}

	/**
	 * 關閉系統時關閉httpClient
	 */
	public static void releaseHttpClient() {
		try {
			httpClient.close();
		} catch (IOException e) {
			logger.error("關閉httpClient異常" + e);
		} finally {
			if (connManager != null) {
				connManager.shutdown();
			}
		}
	}
}

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM