? ? ?版權聲明:本文為博主原創文章,未經博主允許不得轉載。如需轉載請聲明:【轉自 http://blog.csdn.net/xiaoxian8023 】
? ? ?如果看到過我前些天寫過的《[輕松把玩HttpClient之模擬post請求示例](http://blog.csdn.net/xiaoxian8023/article/details/49863967)》這篇文章,你再看本文就是小菜一碟了,如果你順便懂一些NIO,基本上是毫無壓力了。因為HttpAsyncClient相對于HttpClient,就多了一個NIO,這也是為什么支持異步的原因。
? ? ?不過我有一個疑問,雖說NIO是同步非阻塞IO,但是HttpAsyncClient提供了回調的機制,這點兒跟netty很像,所以可以模擬類似于AIO的效果。但是[官網上的例子](http://hc.apache.org/httpcomponents-asyncclient-4.1.x/httpasyncclient/examples/org/apache/http/examples/nio/client/AsyncClientHttpExchange.java)卻基本上都是使用Future<HttpResponse> future = httpclient.execute(request, null);來同步獲得執行結果。
? ? ?好吧,反正我是用回調的方式實現的。代碼基本上跟httpClient那篇一致。不一樣的地方主要有這么2個地方:配置ssl時不一樣;調用execute方式時,使用回調。具體代碼如下:
~~~
package com.tgb.ccl.http.simpledemo;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.HashMap;
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.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.nio.conn.NoopIOSessionStrategy;
import org.apache.http.nio.conn.SchemeIOSessionStrategy;
import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;
import org.apache.http.nio.reactor.ConnectingIOReactor;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
/**
* HttpAsyncClient模擬post請求簡單示例
*
* @author arron
* @date 2015年11月1日 下午2:23:18
* @version 1.0
*/
public class SimpleHttpAsyncClientDemo {
/**
* 設置信任自定義的證書
*
* @param keyStorePath 密鑰庫路徑
* @param keyStorepass 密鑰庫密碼
* @return
*/
public static SSLContext custom(String keyStorePath, String keyStorepass) {
SSLContext sc = null;
FileInputStream instream = null;
KeyStore trustStore = null;
try {
trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
instream = new FileInputStream(new File(keyStorePath));
trustStore.load(instream, keyStorepass.toCharArray());
// 相信自己的CA和所有自簽名的證書
sc = SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()).build();
} catch (KeyStoreException | NoSuchAlgorithmException| CertificateException | IOException | KeyManagementException e) {
e.printStackTrace();
} finally {
try {
instream.close();
} catch (IOException e) {
}
}
return sc;
}
/**
* 繞過驗證
*
* @return
* @throws NoSuchAlgorithmException
* @throws KeyManagementException
*/
public static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {
SSLContext sc = SSLContext.getInstance("SSLv3");
// 實現一個X509TrustManager接口,用于繞過驗證,不用修改里面的方法
X509TrustManager trustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
String paramString) throws CertificateException {
}
@Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
String paramString) throws CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
};
sc.init(null, new TrustManager[] { trustManager }, null);
return sc;
}
/**
* 設置代理
* @param builder
* @param hostOrIP
* @param port
*/
public static HttpAsyncClientBuilder proxy(String hostOrIP, int port){
// 依次是代理地址,代理端口號,協議類型
HttpHost proxy = new HttpHost(hostOrIP, port, "http");
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
return HttpAsyncClients.custom().setRoutePlanner(routePlanner);
}
/**
* 模擬請求
*
* @param url 資源地址
* @param map 參數列表
* @param encoding 編碼
* @param handler 結果處理類
* @return
* @throws NoSuchAlgorithmException
* @throws KeyManagementException
* @throws IOException
* @throws ClientProtocolException
*/
public static void send(String url, Map<String,String> map,final String encoding, final AsyncHandler handler) throws KeyManagementException, NoSuchAlgorithmException, ClientProtocolException, IOException {
//繞過證書驗證,處理https請求
SSLContext sslcontext = createIgnoreVerifySSL();
// 設置協議http和https對應的處理socket鏈接工廠的對象
Registry<SchemeIOSessionStrategy> sessionStrategyRegistry = RegistryBuilder.<SchemeIOSessionStrategy>create()
.register("http", NoopIOSessionStrategy.INSTANCE)
.register("https", new SSLIOSessionStrategy(sslcontext))
.build();
//配置io線程
IOReactorConfig ioReactorConfig = IOReactorConfig.custom().setIoThreadCount(Runtime.getRuntime().availableProcessors()).build();
//設置連接池大小
ConnectingIOReactor ioReactor;
ioReactor = new DefaultConnectingIOReactor(ioReactorConfig);
PoolingNHttpClientConnectionManager connManager = new PoolingNHttpClientConnectionManager(ioReactor, null, sessionStrategyRegistry, null);
//創建自定義的httpclient對象
final CloseableHttpAsyncClient client = proxy("127.0.0.1", 8087).setConnectionManager(connManager).build();
// CloseableHttpAsyncClient client = HttpAsyncClients.createDefault();
//創建post方式請求對象
HttpPost httpPost = new HttpPost(url);
//裝填參數
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
if(map!=null){
for (Entry<String, String> entry : map.entrySet()) {
nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
}
//設置參數到請求對象中
httpPost.setEntity(new UrlEncodedFormEntity(nvps, encoding));
System.out.println("請求地址:"+url);
System.out.println("請求參數:"+nvps.toString());
//設置header信息
//指定報文頭【Content-type】、【User-Agent】
httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");
httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
// Start the client
client.start();
//執行請求操作,并拿到結果(異步)
client.execute(httpPost, new FutureCallback<HttpResponse>() {
@Override
public void failed(Exception ex) {
handler.failed(ex);
close(client);
}
@Override
public void completed(HttpResponse resp) {
String body="";
//這里使用EntityUtils.toString()方式時會大概率報錯,原因:未接受完畢,鏈接已關
try {
HttpEntity entity = resp.getEntity();
if (entity != null) {
final InputStream instream = entity.getContent();
try {
final StringBuilder sb = new StringBuilder();
final char[] tmp = new char[1024];
final Reader reader = new InputStreamReader(instream,encoding);
int l;
while ((l = reader.read(tmp)) != -1) {
sb.append(tmp, 0, l);
}
body = sb.toString();
} finally {
instream.close();
EntityUtils.consume(entity);
}
}
} catch (ParseException | IOException e) {
e.printStackTrace();
}
handler.completed(body);
close(client);
}
@Override
public void cancelled() {
handler.cancelled();
close(client);
}
});
}
/**
* 關閉client對象
*
* @param client
*/
private static void close(CloseableHttpAsyncClient client) {
try {
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
static class AsyncHandler implements IHandler{
@Override
public Object failed(Exception e) {
System.err.println(Thread.currentThread().getName()+"--失敗了--"+e.getClass().getName()+"--"+e.getMessage());
return null;
}
@Override
public Object completed(String respBody) {
System.out.println(Thread.currentThread().getName()+"--獲取內容:"+respBody);
return null;
}
@Override
public Object cancelled() {
System.out.println(Thread.currentThread().getName()+"--取消了");
return null;
}
}
/**
* 回調處理接口
*
* @author arron
* @date 2015年11月10日 上午10:05:40
* @version 1.0
*/
public interface IHandler {
/**
* 處理異常時,執行該方法
* @return
*/
Object failed(Exception e);
/**
* 處理正常時,執行該方法
* @return
*/
Object completed(String respBody);
/**
* 處理取消時,執行該方法
* @return
*/
Object cancelled();
}
}
~~~
? ? ?來一個測試類:
~~~
public static void main(String[] args) throws KeyManagementException, NoSuchAlgorithmException, ClientProtocolException, IOException {
AsyncHandler handler = new AsyncHandler();
String url = "http://php.weather.sina.com.cn/iframe/index/w_cl.php";
Map<String, String> map = new HashMap<String, String>();
map.put("code", "js");
map.put("day", "0");
map.put("city", "上海");
map.put("dfc", "1");
map.put("charset", "utf-8");
send(url, map, "utf-8", handler);
System.out.println("-----------------------------------");
map.put("city", "北京");
send(url, map, "utf-8", handler);
System.out.println("-----------------------------------");
}
~~~
? ? ?測試結果如下:

? ? ?很簡單吧,其實基于HttpAsyncClient的工具類我也進行了封裝,跟HttpClient工具類差不多。代碼都已經提交至:[https://github.com/Arronlong/httpclientUtil](https://github.com/Arronlong/httpclientUtil)。有興趣的自行下載,博客中就不再分享了。
- 前言
- HttpClient3.x之Get請求和Post請求示例
- httpclient3.x中使用HTTPS的方法
- 簡單的利用UrlConnection,后臺模擬http請求
- 輕松把玩HttpClient之模擬post請求示例
- 輕松把玩HttpClient之配置ssl,采用繞過證書驗證實現https
- 輕松把玩HttpClient之配置ssl,采用設置信任自簽名證書實現https
- 輕松把玩HttpClient之設置代理,可以訪問FaceBook
- 輕松把玩HttpClient之封裝HttpClient工具類(一)(現有網上分享中的最強大的工具類)
- 輕松把玩HttpClient之封裝HttpClient工具類(二),插件式配置HttpClient對象
- 輕松把玩HttpClient之封裝HttpClient工具類(三),插件式配置Header
- 輕松把玩HttpClient之封裝HttpClient工具類(四),單線程調用及多線程批量調用測試
- 輕松把玩HttpAsyncClient之模擬post請求示例
- 輕松把玩HttpClient之封裝HttpClient工具類(五),攜帶Cookie的請求
- 輕松把玩HttpClient之封裝HttpClient工具類(六),封裝輸入參數,簡化工具類