接着 上一篇
,總結一下HttpClient發送https請求相關的内容。
先簡單介紹連接配接工廠(
interface org.apache.http.conn.socket.ConnectionSocketFactory
),連接配接工廠主要用于建立、初始化、連接配接socket。 org.apache.http.conn.socket.PlainConnectionSocketFactory
是預設的socket工廠,用于建立無加密(unencrypted)socket對象。建立https需要使用 org.apache.http.conn.ssl.SSLConnectionSocketFactory
, PlainConnectionSocketFactory
和 SSLConnectionSocketFactory
都實作了 ConnectionSocketFactory
。
好了,直接上代碼,代碼實作的功能是,組裝一個發往銀聯的查詢封包(查詢交易結果)。
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
/**
* This example demonstrates how to create secure connections with a custom SSL
* context.
*/
public class ClientCustomSSL {
private static String reqStr = "txnType=00&signMethod=01&certId=68759663125&encoding=UTF-8&merId=777290058110048&bizType=000201&txnSubType=00&signature=k0lrWgeLK%2Fx%2B8ajj15QCYfmdQxZSKBjXUJN0bLt17rp87ptogxWgHAAq7EUt8RlEbxD6GaRngwtdLGiy6are45Gj1dBLJBtW2841WIq4Ywzx3oK6538Kfh9ll91GJcZJGYz8LuJoZfii7HFPlpl1ZsPZbbdKP6WFVHNMnGnL9nk9QSa%2BihXGpyK%2Fy1FA42AJpfc%2FTT3BV6C%2FxpoEhXzVckHnniVnCpLdGnPfZOd76wK%2Fa%2BALNmniwUZmMj9uNPwnONIIwL%2FFqrqQinQArolW%2FrcIt9NL7qKvQujM%2BdRvd1fboAHI5bZC3ktVPB0s5QFfsRhSRFghVi4RHOzL8ZG%2FVQ%3D%3D&orderId=20160309145206&version=5.0.0&txnTime=20160309145206&accessType=0";
private static String url = "https://101.231.204.80:5000/gateway/api/queryTrans.do";
// 信任管理器
private static X509TrustManager tm = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
public final static void main(String[] args) throws Exception {
long starttime = System.currentTimeMillis();
SSLContext sslContext = SSLContext.getInstance("TLS");
// 初始化SSL上下文
sslContext.init(null, new TrustManager[] { tm }, null);
// SSL套接字連接配接工廠,NoopHostnameVerifier為信任所有伺服器
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext,NoopHostnameVerifier.INSTANCE);
/**
* 通過setSSLSocketFactory(sslsf)保證httpclient執行個體能發送Https請求
*/
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).setMaxConnTotal(50)
.setMaxConnPerRoute(50).setDefaultRequestConfig(RequestConfig.custom()
.setConnectionRequestTimeout(60000).setConnectTimeout(60000).setSocketTimeout(60000).build())
.build();
try {
HttpPost httppost = new HttpPost(url);
// 設定參數,參數含義不需要了解
Map<String, String> map = new HashMap<String, String>();
map.put("txnType","00");
map.put("signMethod","01");
map.put("certId","68759663125");
map.put("encoding","UTF-8");
map.put("merId","777290058110048");
map.put("bizType","000201");
map.put("txnSubType","00");
map.put("signature","k0lrWgeLK%2Fx%2B8ajj15QCYfmdQxZSKBjXUJN0bLt17rp87ptogxWgHAAq7EUt8RlEbxD6GaRngwtdLGiy6are45Gj1dBLJBtW2841WIq4Ywzx3oK6538Kfh9ll91GJcZJGYz8LuJoZfii7HFPlpl1ZsPZbbdKP6WFVHNMnGnL9nk9QSa%2BihXGpyK%2Fy1FA42AJpfc%2FTT3BV6C%2FxpoEhXzVckHnniVnCpLdGnPfZOd76wK%2Fa%2BALNmniwUZmMj9uNPwnONIIwL%2FFqrqQinQArolW%2FrcIt9NL7qKvQujM%2BdRvd1fboAHI5bZC3ktVPB0s5QFfsRhSRFghVi4RHOzL8ZG%2FVQ%3D%3D");
map.put("orderId","20160309145206");
map.put("version","5.0.0");
map.put("txnTime","20160309145206");
map.put("accessType","0");
List<NameValuePair> list = new ArrayList<NameValuePair>();
Iterator<Entry<String, String>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Entry<String, String> elem = (Entry<String, String>) iterator.next();
list.add(new BasicNameValuePair(elem.getKey(), elem.getValue()));
}
if (list.size() > 0) {
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8");
httppost.setEntity(entity);
}
System.out.println("executing request " + httppost.getRequestLine());
CloseableHttpResponse response = httpclient.execute(httppost);
try {
HttpEntity entity = response.getEntity();
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
if (entity != null) {
System.out.println("Response content length: " + entity.getContentLength());
}
String s = EntityUtils.toString(entity,"UTF-8");
System.out.println("應答内容:" + s);
EntityUtils.consume(entity);
} finally {
response.close();
}
} finally {
httpclient.close();
}
long endtime = System.currentTimeMillis();
System.out.println("耗時:" + (endtime-starttime) + "ms");
}
}
使用注冊器可以保證既能發送http請求也能發送httpsclient請求,代碼塊如下:
int httpReqTimeOut = 60000;//60秒
SSLContext sslContext = SSLContext.getInstance("TLS");
// 初始化SSL上下文
sslContext.init(null, new TrustManager[] { tm }, null);
// SSL套接字連接配接工廠,NoopHostnameVerifier為信任所有伺服器
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext,NoopHostnameVerifier.INSTANCE);
// 注冊http套接字工廠和https套接字工廠
Registry<ConnectionSocketFactory> r = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", sslsf)
.build();
// 連接配接池管理器
PoolingHttpClientConnectionManager pcm = new PoolingHttpClientConnectionManager(r);
pcm.setMaxTotal(maxConnTotal);//連接配接池最大連接配接數
pcm.setDefaultMaxPerRoute(maxConnPerRoute);//每個路由最大連接配接數
/**
* 請求參數配置
* connectionRequestTimeout:
* 從連接配接池中擷取連接配接的逾時時間,超過該時間未拿到可用連接配接,
* 會抛出org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
* connectTimeout:
* 連接配接上伺服器(握手成功)的時間,超出該時間抛出connect timeout
* socketTimeout:
* 伺服器傳回資料(response)的時間,超過該時間抛出read timeout
*/
RequestConfig requestConfig = RequestConfig.custom()
.setConnectionRequestTimeout(httpReqTimeOut)
.setConnectTimeout(httpReqTimeOut)
.setSocketTimeout(httpReqTimeOut)
.build();
/**
* 構造closeableHttpClient對象
*/
closeableHttpClient = HttpClients.custom()
.setDefaultRequestConfig(requestConfig)
.setConnectionManager(pcm)
.setRetryHandler(retryHandler)
.build();
關鍵代碼為:
// 注冊http套接字工廠和https套接字工廠
Registry<ConnectionSocketFactory> r = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", sslsf)
.build();