http client 工具類
HttpConn
public class HttpConn {
private final static Logger logger = LoggerFactory.getLogger(HttpConn.class);
//MIME-TYPE
public static final String MIME_TYPE_PLAIN = "text/plain";
public static final String MIME_TYPE_XML = "text/xml";
public static final String MIME_TYPE_HTML = "text/html";
public static final String MIME_TYPE_JSON = "application/json";
//REQUEST METHOD
public static final String METHOD_GET = "GET";
public static final String METHOD_POST = "POST";
//HTTP STATUS
public static final int HTTP_RESSTATUS_SUCCESS = 200;
public static final int HTTP_RESSTATUS_NOT_FOUND = 404;
//Default Values
public static final String DETAULT_ENCODING = "UTF-8";
public static final Charset DEFAULT_CHARSET = Consts.UTF_8;
public static final int REQUEST_TIMEOUT = 5 * 1000; // 請求超時時間
public static final int CONNECTION_TIMEOUT = 10 * 1000; // 連接超時時間
public static final int SOCKET_TIMEOUT = 10 * 1000; // 數據傳輸超時
public static final int POOL_MAX_SIZE = 200; // 連接池最大連接數
public static final int POOL_MAX_SIZE_PER_ROUTER = 200; // 每個路由最大連接數
//Request Params
private String reqUrl;
private String reqMethod;
private Map<String, String> reqParams;//請求參數
private String reqPostString;//post內容
private String reqCharset;
private String reqContentType;//請求內容類型
private String reqFileKey;//上傳文件在form-data的key值
private String reqFilePath;//上傳的文件路徑
//Response Infos
private int resCode;
private boolean resSuccess = false;//是否正常響應,即返回200
private String resStatues;
private long resLength;
private String resEncoding;
private String resContentType;
private String resBody;
private String resFilePath;
private boolean resFileSaveSuccess = false;//響應文件是否保存成功
//
private static PoolingHttpClientConnectionManager cm = null;
private static CloseableHttpClient client = null;
private HttpUriRequest request = null;
private CloseableHttpResponse response = null;
/**
* 初始化連接池與Client
* */
static{
try {
// 初始化SSL環境
SSLContextBuilder sslContextbuilder = new SSLContextBuilder();
sslContextbuilder.useTLS();
SSLContext sslContext = sslContextbuilder.loadTrustMaterial(null, new TrustStrategy() {
// 信任所有
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException
{
return true;
}
}).build();
//注冊協議
ConnectionSocketFactory plainCSF = PlainConnectionSocketFactory.INSTANCE;
ConnectionSocketFactory sslCSF = new SSLConnectionSocketFactory(sslContext, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
.register("http", plainCSF)
.register("https", sslCSF)
.build();
// 創建連接池
cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
// 初始化Socket配置
SocketConfig socketConfig = SocketConfig.custom()
.setTcpNoDelay(true)
.build();
cm.setDefaultSocketConfig(socketConfig);
// Http消息約束
// MessageConstraints messageConstraints = MessageConstraints.custom().
// setMaxHeaderCount(200).
// setMaxLineLength(2000).build();
// http連接設置
ConnectionConfig connectionConfig = ConnectionConfig.custom()
.setMalformedInputAction(CodingErrorAction.IGNORE) //忽略不合法的輸入
.setUnmappableInputAction(CodingErrorAction.IGNORE) //忽略不匹配的輸入
.setCharset(DEFAULT_CHARSET)
// .setMessageConstraints(messageConstraints)
.build();
cm.setDefaultConnectionConfig(connectionConfig);
cm.setMaxTotal(POOL_MAX_SIZE); //連接池最大連接數
cm.setDefaultMaxPerRoute(POOL_MAX_SIZE_PER_ROUTER); //每個路由最大連接數
// 請求設置
RequestConfig requestConfig = RequestConfig.custom()
.setConnectionRequestTimeout(REQUEST_TIMEOUT) //請求超時
.setSocketTimeout(SOCKET_TIMEOUT) //Socket超時
.setConnectTimeout(CONNECTION_TIMEOUT) //連接超時
.build();
// 創建HttpClient
client = HttpClients.custom()
.disableRedirectHandling()
.setConnectionManager(cm)
.setDefaultRequestConfig(requestConfig)
.build();
// 啟動連接池監控線程
HttpConnMonitorThread monitor = new HttpConnMonitorThread(cm);
monitor.start();
} catch (KeyManagementException e) {
logger.error("", e);
} catch (NoSuchAlgorithmException e) {
logger.error("", e);
} catch (KeyStoreException e) {
logger.error("", e);
}
}
/**
* 設置請求、連接、獲取響應
* */
public boolean connect() throws ParseException, UnsupportedEncodingException, IOException {
try {
setReqInfo();
if(CommonUtil.isEmpty(this.request)){
throw new RuntimeException("HttpConn ,初始化請求失敗!");
}
//執行連接,返回響應
HttpClientContext context = HttpClientContext.create();
this.response = client.execute(this.request, context);
//處理響應結果
if(CommonUtil.isEmpty(this.response)){
throw new RuntimeException("HttpConn ,響應獲取失敗!");
}
setResInfo();
} finally {
try {
if(this.response != null)
this.response.close();
} catch (IOException e) {
logger.error(e.getMessage());
}
}
return true;
}
/**
* 設置請求參數
* */
private void setReqInfo() throws ParseException, UnsupportedEncodingException, IOException{
if(!CommonUtil.isEmpty(this.reqFilePath))//上傳,使用POST
this.reqMethod = METHOD_POST;
if(!CommonUtil.isEmpty(this.reqPostString))//post參數,使用POST
this.reqMethod = METHOD_POST;
if(CommonUtil.isEmpty(this.reqMethod))
this.reqMethod = METHOD_GET;
if(CommonUtil.isEmpty(this.reqContentType)) //設置內容類型,默認為text/plain
this.reqContentType = MIME_TYPE_PLAIN;
if(CommonUtil.isEmpty(this.reqCharset)) //設置編碼格式
this.reqCharset = DETAULT_ENCODING;
//將請求參數轉換為字符串形式
String paramString = null;
if(!CommonUtil.isEmpty(this.reqParams)){
List<NameValuePair> paramList = new ArrayList<NameValuePair>();
Iterator<Map.Entry<String, String>> it = this.reqParams.entrySet().iterator();
while(it.hasNext()){
Map.Entry<String, String> entry = it.next();
paramList.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
paramString = EntityUtils.toString(new UrlEncodedFormEntity(paramList, this.reqCharset == null?DETAULT_ENCODING : this.reqCharset));
}
//GET請求
if(this.reqMethod.equalsIgnoreCase(METHOD_GET)){
//設置請求參數
if(!CommonUtil.isEmpty(paramString)){
if(this.reqUrl.trim().lastIndexOf("?") == -1){
this.reqUrl += "?" + paramString;
}else{
this.reqUrl += "&" + paramString;
}
}
//創建Get請求
HttpGet get = new HttpGet(this.reqUrl);
this.request = get;
}
//POST請求
else if(this.reqMethod.equals(METHOD_POST)){
HttpPost post = new HttpPost(this.reqUrl);
//post請求參數
if(!CommonUtil.isEmpty(this.reqPostString) || !CommonUtil.isEmpty(paramString)){
reqPostString = (reqPostString==null ? paramString : reqPostString);
StringEntity entity = null;
entity = new StringEntity(this.reqPostString, ContentType.create(this.reqContentType,this.reqCharset));
post.setEntity(entity);
}
//上傳文件
else if(!CommonUtil.isEmpty(this.reqFilePath)){
MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
//以瀏覽器兼容模式運行,防止文件名亂碼
entityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
// entityBuilder.setCharset(Consts.UTF_8);//設置編碼格式
//設置文件信息
File uploadFile = new File(this.reqFilePath);
if(!uploadFile.exists()){
throw new RuntimeException("HttpConn:\""+reqFilePath+"\"路徑不存在!");
}else{
if(CommonUtil.isEmpty(this.reqFileKey))
throw new RuntimeException("HttpConn: resFileKey為空!");
entityBuilder.addBinaryBody(this.reqFileKey, uploadFile);
}
//設置參數信息
if(!CommonUtil.isEmpty(this.reqParams)){
Iterator<Map.Entry<String, String>> it = this.reqParams.entrySet().iterator();
while(it.hasNext()){
Map.Entry<String, String> entry = it.next();
String key = entry.getKey();
StringBody body = new StringBody(entry.getValue(), ContentType.create("text/plain", DETAULT_ENCODING));
entityBuilder.addPart(key, body);
}
}
post.setEntity(entityBuilder.build());
}
this.request = post;
}
}
/**
* 處理響應數據
* @throws IllegalStateException
* @throws IOException
*/
private void setResInfo() throws IllegalStateException, IOException {
HttpEntity resEntity = this.response.getEntity();
//返回狀態
this.resCode = this.response.getStatusLine().getStatusCode();
this.resStatues = this.response.getStatusLine().toString();
this.resLength = resEntity.getContentLength();
if(!CommonUtil.isEmpty(resEntity.getContentEncoding()))
this.resEncoding = resEntity.getContentEncoding().getValue();
if(this.resCode == HTTP_RESSTATUS_SUCCESS){
resSuccess = true;
//返回數據
this.resContentType = resEntity.getContentType().getValue();
if(CommonUtil.isEmpty(this.resEncoding)){
this.resEncoding = getEncoding(this.resContentType);
}
InputStream is = null;
FileOutputStream fos = null;
try{
is = resEntity.getContent();
//保存為文件
if(!CommonUtil.isEmpty(this.resFilePath)){
if(!CommonUtil.isFilePath(this.resFilePath)){
//從請求頭獲取文件名
String fileName = getValueFromHeader("Content-disposition", "filename");
if(fileName != null){
this.resFilePath += "_"+fileName;
}
}
File downFile = new File(this.resFilePath);
downFile.getParentFile().mkdirs();
fos = new FileOutputStream(downFile);
resEntity.writeTo(fos);
this.resFileSaveSuccess = true;
}
//保存為字符串
else{
if(CommonUtil.isEmpty(this.resEncoding))
this.resBody = EntityUtils.toString(resEntity, Consts.UTF_8);
else
this.resBody = EntityUtils.toString(resEntity, this.resEncoding);
}
}finally{
try {
if(is != null)
is.close();
if(fos != null)
fos.close();
} catch (Exception e) {
throw new RuntimeException("HttpConn : " + e.getMessage());
}
}
}else{
this.request.abort();//中止請求
throw new RuntimeException("HttpConn ,error status code : " + this.resCode);
}
//銷毀
EntityUtils.consume(resEntity);
}
/**
* 從content-type獲取編碼格式
* @param contentType
* @return
*/
private String getEncoding(String contentType) {
String encoding = null;
int tmp = contentType.indexOf(";");
if(tmp > 0){
encoding = contentType.substring(tmp+1);
encoding = encoding.trim();
tmp = encoding.indexOf("=");
if(tmp > 0){
String[] entry = encoding.split("=");
if(entry[0].equalsIgnoreCase("charset") || entry[0].equalsIgnoreCase("encoding"))
encoding = entry[1].trim();
}
}
return encoding;
}
/**
* 從請求頭中獲取參數值
* @param headerName
* @param key
* @return
*/
private String getValueFromHeader(String headerName, String key) {
String value = null;
Header header = this.response.getFirstHeader(headerName);
if(!CommonUtil.isEmpty(header)){
if(CommonUtil.isEmpty(key)){
value = header.getValue();
}else{
HeaderElement[] elms = header.getElements();
for(HeaderElement elm : elms){
NameValuePair pair = elm.getParameterByName(key);
if(pair != null){
value = pair.getValue();
break;
}
}
}
}
return value;
}
public void setReqFilePath(String reqFileKey, String reqFilePath) {
this.reqFileKey = reqFileKey;
this.reqFilePath = reqFilePath;
}
public int getResCode() {
return resCode;
}
public String getResStatues() {
return resStatues;
}
public String getResType() {
return resContentType;
}
public String getResBody() {
return resBody;
}
public void setReqUrl(String reqUrl) {
this.reqUrl = reqUrl;
}
public void setReqMethod(String reqMethod) {
this.reqMethod = reqMethod;
}
public void setReqParams(Map<String, String> reqParams) {
this.reqParams = reqParams;
}
public void setReqPostString(String reqPostString) {
this.reqPostString = reqPostString;
}
public void setReqContentType(String reqContentType) {
this.reqContentType = reqContentType;
}
public void setResFilePath(String resFilePath) {
this.resFilePath = resFilePath;
}
public long getResLength() {
return resLength;
}
public String getResEncoding() {
return resEncoding;
}
public String getResContentType() {
return resContentType;
}
public boolean isResFileSaveSuccess() {
return resFileSaveSuccess;
}
public void setReqCharset(String reqCharset) {
this.reqCharset = reqCharset;
}
public boolean isResSuccess() {
return resSuccess;
}
public void setResSuccess(boolean resSuccess) {
this.resSuccess = resSuccess;
}
}
HttpConnMonitorThread
public class HttpConnMonitorThread extends Thread{
private final static Logger logger = LoggerFactory.getLogger(HttpConnMonitorThread.class);
private final HttpClientConnectionManager cm;
private volatile boolean shutdown;
private final static int WATING_TIME = 60 * 1000; // 輪詢時間
private final static int IDLE_TIME = 30; // 空閑時間
public HttpConnMonitorThread(HttpClientConnectionManager cm) {
super();
this.cm = cm;
}
@Override
public void run() {
try {
while (!shutdown) {
synchronized (this) {
wait(WATING_TIME);
// 關閉過期連接
cm.closeExpiredConnections();
logger.info(">>>>>close expired connections.");
// 關閉空閑連接
cm.closeIdleConnections(IDLE_TIME, TimeUnit.SECONDS);
logger.info(">>>>>close idle connections.");
}
}
} catch (InterruptedException ex) {
logger.error("HttpConn Monitor error! ", ex);
}
}
/**
* 關閉輪詢
*/
public void shutdown() {
shutdown = true;
synchronized (this) {
notifyAll();
}
}
} 本文由用戶 RegPoate 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!