在游戲項目開發中,經常會向其它的服務發送一些Http請求,獲取一些數據或驗證。比如充值,SDK驗證等。如果每次都重新創建一個新的HttpClient對象的話,當並發上來時,容易出現異常或連接失敗,超時。這里可以使用HttpClient的連接池配置,減少HttpClient創建的數量,減少資源開銷。
package com.mygame.common.utils; import java.io.IOException; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import org.apache.http.Header; 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.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.conn.ssl.TrustSelfSignedStrategy; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.ssl.SSLContextBuilder; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alibaba.fastjson.JSON; public class GameHttpClient { private static Logger logger = LoggerFactory.getLogger(GameHttpClient.class); // 池化管理 private static PoolingHttpClientConnectionManager poolConnManager = null; private static CloseableHttpClient httpClient;// 它是線程安全的,所有的線程都可以使用它一起發送http請求 static { try { System.out.println("初始化HttpClientTest~~~開始"); SSLContextBuilder builder = new SSLContextBuilder(); builder.loadTrustMaterial(null, new TrustSelfSignedStrategy()); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build()); // 配置同時支持 HTTP 和 HTPPS Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", sslsf).build(); // 初始化連接管理器 poolConnManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); poolConnManager.setMaxTotal(640);// 同時最多連接數 // 設置最大路由 poolConnManager.setDefaultMaxPerRoute(320); // 此處解釋下MaxtTotal和DefaultMaxPerRoute的區別: // 1、MaxtTotal是整個池子的大小; // 2、DefaultMaxPerRoute是根據連接到的主機對MaxTotal的一個細分;比如: // MaxtTotal=400 DefaultMaxPerRoute=200 // 而我只連接到http://www.abc.com時,到這個主機的並發最多只有200;而不是400; // 而我連接到http://www.bac.com 和 // http://www.ccd.com時,到每個主機的並發最多只有200;即加起來是400(但不能超過400);所以起作用的設置是DefaultMaxPerRoute // 初始化httpClient httpClient = getConnection(); System.out.println("初始化HttpClientTest~~~結束"); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (KeyStoreException e) { e.printStackTrace(); } catch (KeyManagementException e) { e.printStackTrace(); } } public static CloseableHttpClient getConnection() { RequestConfig config = RequestConfig.custom().setConnectTimeout(5000).setConnectionRequestTimeout(5000).setSocketTimeout(5000).build(); CloseableHttpClient httpClient = HttpClients.custom() // 設置連接池管理 .setConnectionManager(poolConnManager) .setDefaultRequestConfig(config) // 設置重試次數 .setRetryHandler(new DefaultHttpRequestRetryHandler(2, false)).build(); return httpClient; } public static String httpGet(String url) { HttpGet httpGet = new HttpGet(url); CloseableHttpResponse response = null; try { response = httpClient.execute(httpGet); String result = EntityUtils.toString(response.getEntity()); int code = response.getStatusLine().getStatusCode(); if (code == HttpStatus.SC_OK) { return result; } else { logger.error("請求{}返回錯誤碼:{},{}", url, code,result); return null; } } catch (IOException e) { logger.error("http請求異常,{}",url,e); } finally { try { if (response != null) response.close(); } catch (IOException e) { e.printStackTrace(); } } return null; } public static String post(String uri, Object params, Header... heads) { HttpPost httpPost = new HttpPost(uri); CloseableHttpResponse response = null; try { StringEntity paramEntity = new StringEntity(JSON.toJSONString(params)); paramEntity.setContentEncoding("UTF-8"); paramEntity.setContentType("application/json"); httpPost.setEntity(paramEntity); if (heads != null) { httpPost.setHeaders(heads); } response = httpClient.execute(httpPost); int code = response.getStatusLine().getStatusCode(); String result = EntityUtils.toString(response.getEntity()); if (code == HttpStatus.SC_OK) { return result; } else { logger.error("請求{}返回錯誤碼:{},請求參數:{},{}", uri, code, params,result); return null; } } catch (IOException e) { logger.error("收集服務配置http請求異常", e); } finally { try { if(response != null) { response.close(); } } catch (IOException e) { e.printStackTrace(); } } return null; } }
QQ交流群:66728073,197321069