在游戲項目開發中,經常會向其它的服務發送一些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

