HttpClient 網路傳送工具使用技巧
阿新 • • 發佈:2018-12-12
平時專案中一般用來發送Http請求的工具可以用HttpConnectionURL工具,但是它是Java自帶的,在net包下,而且一般連線不能重用,所以用起來比較麻煩,所以apache下有一個已經封裝好的HttpClient工具包,它的每個版本變化都比較大,使用起來都不一樣,我目前使用的是4.5.3版本。
新增POM依賴
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.3</version> </dependency>
程式碼示例
/** * 文 件 名: HttpProxy * 版 權: Quanten Technologies Co., Ltd. Copyright YYYY-YYYY, All rights reserved * 描 述: <描述> * 修 改 人: zping * 修改時間: 2017/9/15 0015 * 跟蹤單號: <跟蹤單號> * 修改單號: <修改單號> * 修改內容: <修改內容> */ package com.pine.chown.http; import org.apache.commons.codec.Charsets; import org.apache.http.Consts; import org.apache.http.HttpEntity; import org.apache.http.HttpStatus; 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.config.ConnectionConfig; import org.apache.http.conn.HttpHostConnectException; 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.protocol.HTTP; import org.apache.http.util.EntityUtils; import java.util.Iterator; import java.util.Map; import java.util.Set; /** * <HTTP 傳送請求工具> * * @author Pine Chown * @version 2017/9/15 0015 * @see [相關類/方法] * @since [產品/模組版本] */ public final class HttpProxy { /** * HTTP CLIENT 連線物件 */ private static CloseableHttpClient httpClient; /** * 請求資料型別 */ private static final String APPLICATION_JSON = "application/json"; /** * 資料型別:octet-stream */ private static final String APPLICATION_OCTET_STREAM = "application/octet-stream"; /** * 預設編碼 */ private static final String CONTENT_ENCODE_TYPE = "UTF-8"; /** * 知識點1:路由(MAX_PER_ROUTE)是對最大連線數(MAX_TOTAL)的細分,整個連線池的限制數量實際使用DefaultMaxPerRoute並非MaxTotal。 * 設定過小無法支援大併發(ConnectionPoolTimeoutException: Timeout waiting for connection from pool) */ private static final int DEFAULT_MAX_TOTAL = 512; /** * 針對某個域名的最大連線數 */ private static final int DEFAULT_MAX_PER_ROUTE = 50; /** * 知識點2:跟目標服務建立連線超時時間,根據自己的業務調整 */ private static final int DEFAULT_CONNECTION_TIMEOUT = 6000; /** * 知識點3:請求的超時時間(建聯後,獲取response的返回等待時間) */ private static final int DEFAULT_SOCKET_TIMEOUT = 6000; /** * 知識點4:從連線池中獲取連線的超時時間 */ private static final int DEFAULT_TIMEOUT = 500; /** * 私有構造器 */ private HttpProxy () { ConnectionConfig config = ConnectionConfig.custom ().setCharset (Charsets.UTF_8).build (); RequestConfig defaultRequestConfig = RequestConfig.custom ().setConnectTimeout (DEFAULT_CONNECTION_TIMEOUT) .setSocketTimeout (DEFAULT_SOCKET_TIMEOUT).setConnectionRequestTimeout (DEFAULT_TIMEOUT).build (); PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager (); cm.setDefaultMaxPerRoute (DEFAULT_MAX_PER_ROUTE); cm.setDefaultConnectionConfig (config); httpClient = HttpClients.custom ().setMaxConnPerRoute (DEFAULT_MAX_PER_ROUTE) .setMaxConnTotal (DEFAULT_MAX_TOTAL) /*.setRetryHandler((exception, executionCount, context) -> executionCount <= 3 && (exception instanceof NoHttpResponseException || exception instanceof ClientProtocolException || exception instanceof SocketTimeoutException || exception instanceof ConnectTimeoutException))*/.setConnectionManager (cm) .setDefaultRequestConfig (defaultRequestConfig).build (); } /** * @param url 請求地址 * @param xml xml報文 * @param header 請求頭 * @return 請求返回json * @throws Exception */ public String doPost (String url, String xml, Map<String, String> header) throws Exception { CloseableHttpResponse response = null; HttpPost post = null; HttpEntity entity = null; try { post = new HttpPost (url); post.addHeader (HTTP.CONTENT_TYPE, APPLICATION_JSON); StringEntity se = new StringEntity (xml, Consts.UTF_8); if (null != header && 0 < header.size ()) { Set<String> headerNames = header.keySet (); Iterator<String> its = headerNames.iterator (); while (its.hasNext ()) { String heardName = its.next (); post.addHeader (heardName, header.get (heardName)); } } post.setEntity (se); response = httpClient.execute (post); if (HttpStatus.SC_OK == response.getStatusLine ().getStatusCode ()) { entity = response.getEntity (); if (null != entity) { String responseStr = EntityUtils.toString (entity, CONTENT_ENCODE_TYPE); return responseStr; } } else { return ""; } } catch (HttpHostConnectException e) { e.printStackTrace (); // 釋放連線 if (null != entity) { EntityUtils.consume (entity); } } catch (Exception e) { e.printStackTrace (); // 釋放連線 if (null != entity) { EntityUtils.consume (entity); } } finally { if (null != post) { post.releaseConnection (); } // 釋放連線 if (null != entity) { EntityUtils.consume (entity); } if (response != null) { try { response.close (); } catch (Exception e) { e.printStackTrace (); } } } return ""; } /** * @param url 請求地址 * @param queryString xml報文 * @param header 請求頭 * @return 請求返回json * @throws Exception */ public String doGet (String url, String queryString, Map<String, String> header) throws Exception { CloseableHttpResponse response = null; HttpGet httpGet = null; HttpEntity entity = null; try { httpGet = new HttpGet (url); //httpGet.addHeader (HTTP.CONTENT_TYPE, APPLICATION_JSON); if (null != header && 0 < header.size ()) { Set<String> headerNames = header.keySet (); Iterator<String> its = headerNames.iterator (); while (its.hasNext ()) { String heardName = its.next (); httpGet.addHeader (heardName, header.get (heardName)); } } response = httpClient.execute (httpGet); if (HttpStatus.SC_OK == response.getStatusLine ().getStatusCode ()) { entity = response.getEntity (); if (null != entity) { String responseStr = EntityUtils.toString (entity, CONTENT_ENCODE_TYPE); return responseStr; } } else { return ""; } } catch (HttpHostConnectException e) { e.printStackTrace (); // 釋放連線 if (null != entity) { EntityUtils.consume (entity); } } catch (Exception e) { e.printStackTrace (); // 釋放連線 if (null != entity) { EntityUtils.consume (entity); } } finally { if (null != httpGet) { httpGet.releaseConnection (); } // 釋放連線 if (null != entity) { EntityUtils.consume (entity); } if (response != null) { try { response.close (); } catch (Exception e) { e.printStackTrace (); } } } return ""; } /** * 靜態內部類 */ private static class SingletonHolder { private static final HttpProxy HTTP_PROXY = new HttpProxy (); } /** * 獲取單例 * * @return MultiThreadHttpManager */ public static final HttpProxy getInstance () { return SingletonHolder.HTTP_PROXY; } }
解釋:
由於HttpProxy是一個工具類,所以我們採用單例模式,通過考慮單例的實現方式,通過懶載入的方式,我們最終採用靜態內部類的方式實現單例,這樣的好處:
- 系統啟動外部類初始化,此時內部類還沒有初始化
- 內部類只有在getInstance()的時候才會被載入(實現了延遲懶載入)
- 執行緒安全(內部類在載入初始化的時候是執行緒安全的,保證了只有一個例項物件)