轻松把玩HttpAsyncClient之模拟post请求示例

如果看到过我前些天写过的《轻松把玩HttpClient之模拟post请求示例》这篇文章,你再看本文就是小菜一碟了,如果你顺便懂一些NIO,基本上是毫无压力了。因为HttpAsyncClient相对于HttpClient,就多了一个NIO,这也是为什么支持异步的原因。


不过我有一个疑问,虽说NIO是同步非阻塞IO,但是HttpAsyncClient提供了回调的机制,这点儿跟netty很像,所以可以模拟类似于AIO的效果。但是官网上的例子却基本上都是使用Future<HttpResponse> future = httpclient.execute(request, null);来同步获得执行结果。


好吧,反正我是用回调的方式实现的。代码基本上跟httpClient那篇一致。不一样的地方主要有这么2个地方:配置ssl时不一样;调用execute方式时,使用回调。具体代码如下:

[java]  view plain  copy
 print ?
  1. package com.tgb.ccl.http.simpledemo;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileInputStream;  
  5. import java.io.IOException;  
  6. import java.io.InputStream;  
  7. import java.io.InputStreamReader;  
  8. import java.io.Reader;  
  9. import java.security.KeyManagementException;  
  10. import java.security.KeyStore;  
  11. import java.security.KeyStoreException;  
  12. import java.security.NoSuchAlgorithmException;  
  13. import java.security.cert.CertificateException;  
  14. import java.util.ArrayList;  
  15. import java.util.HashMap;  
  16. import java.util.List;  
  17. import java.util.Map;  
  18. import java.util.Map.Entry;  
  19.   
  20. import javax.net.ssl.SSLContext;  
  21. import javax.net.ssl.TrustManager;  
  22. import javax.net.ssl.X509TrustManager;  
  23.   
  24. import org.apache.http.HttpEntity;  
  25. import org.apache.http.HttpHost;  
  26. import org.apache.http.HttpResponse;  
  27. import org.apache.http.NameValuePair;  
  28. import org.apache.http.ParseException;  
  29. import org.apache.http.client.ClientProtocolException;  
  30. import org.apache.http.client.entity.UrlEncodedFormEntity;  
  31. import org.apache.http.client.methods.HttpPost;  
  32. import org.apache.http.concurrent.FutureCallback;  
  33. import org.apache.http.config.Registry;  
  34. import org.apache.http.config.RegistryBuilder;  
  35. import org.apache.http.conn.ssl.TrustSelfSignedStrategy;  
  36. import org.apache.http.impl.conn.DefaultProxyRoutePlanner;  
  37. import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;  
  38. import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;  
  39. import org.apache.http.impl.nio.client.HttpAsyncClients;  
  40. import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;  
  41. import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;  
  42. import org.apache.http.impl.nio.reactor.IOReactorConfig;  
  43. import org.apache.http.message.BasicNameValuePair;  
  44. import org.apache.http.nio.conn.NoopIOSessionStrategy;  
  45. import org.apache.http.nio.conn.SchemeIOSessionStrategy;  
  46. import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;  
  47. import org.apache.http.nio.reactor.ConnectingIOReactor;  
  48. import org.apache.http.ssl.SSLContexts;  
  49. import org.apache.http.util.EntityUtils;  
  50.   
  51. /**  
  52.  * HttpAsyncClient模拟post请求简单示例 
  53.  *  
  54.  * @author arron 
  55.  * @date 2015年11月1日 下午2:23:18  
  56.  * @version 1.0  
  57.  */  
  58. public class SimpleHttpAsyncClientDemo {  
  59.       
  60.     /** 
  61.      * 设置信任自定义的证书 
  62.      *   
  63.      * @param keyStorePath      密钥库路径 
  64.      * @param keyStorepass      密钥库密码 
  65.      * @return 
  66.      */  
  67.     public static SSLContext custom(String keyStorePath, String keyStorepass) {  
  68.         SSLContext sc = null;  
  69.         FileInputStream instream = null;  
  70.         KeyStore trustStore = null;  
  71.         try {  
  72.             trustStore = KeyStore.getInstance(KeyStore.getDefaultType());  
  73.             instream = new FileInputStream(new File(keyStorePath));  
  74.             trustStore.load(instream, keyStorepass.toCharArray());  
  75.             // 相信自己的CA和所有自签名的证书  
  76.             sc = SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()).build();  
  77.         } catch (KeyStoreException | NoSuchAlgorithmException| CertificateException | IOException | KeyManagementException e) {  
  78.             e.printStackTrace();  
  79.         } finally {  
  80.             try {  
  81.                 instream.close();  
  82.             } catch (IOException e) {  
  83.             }  
  84.         }  
  85.         return sc;  
  86.     }  
  87.       
  88.     /** 
  89.      * 绕过验证 
  90.      *   
  91.      * @return 
  92.      * @throws NoSuchAlgorithmException  
  93.      * @throws KeyManagementException  
  94.      */  
  95.     public static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {  
  96.         SSLContext sc = SSLContext.getInstance("SSLv3");  
  97.   
  98.         // 实现一个X509TrustManager接口,用于绕过验证,不用修改里面的方法  
  99.         X509TrustManager trustManager = new X509TrustManager() {  
  100.             @Override  
  101.             public void checkClientTrusted(  
  102.                     java.security.cert.X509Certificate[] paramArrayOfX509Certificate,  
  103.                     String paramString) throws CertificateException {  
  104.             }  
  105.   
  106.             @Override  
  107.             public void checkServerTrusted(  
  108.                     java.security.cert.X509Certificate[] paramArrayOfX509Certificate,  
  109.                     String paramString) throws CertificateException {  
  110.             }  
  111.   
  112.             @Override  
  113.             public java.security.cert.X509Certificate[] getAcceptedIssuers() {  
  114.                 return null;  
  115.             }  
  116.         };  
  117.         sc.init(nullnew TrustManager[] { trustManager }, null);  
  118.         return sc;  
  119.     }  
  120.   
  121.     /** 
  122.      * 设置代理 
  123.      * @param builder 
  124.      * @param hostOrIP 
  125.      * @param port 
  126.      */  
  127.     public static HttpAsyncClientBuilder proxy(String hostOrIP, int port){  
  128.         // 依次是代理地址,代理端口号,协议类型    
  129.         HttpHost proxy = new HttpHost(hostOrIP, port, "http");    
  130.         DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);  
  131.         return HttpAsyncClients.custom().setRoutePlanner(routePlanner);  
  132.     }  
  133.       
  134.     /** 
  135.      * 模拟请求 
  136.      *  
  137.      * @param url               资源地址 
  138.      * @param map           参数列表 
  139.      * @param encoding  编码 
  140.      * @param handler       结果处理类 
  141.      * @return 
  142.      * @throws NoSuchAlgorithmException  
  143.      * @throws KeyManagementException  
  144.      * @throws IOException  
  145.      * @throws ClientProtocolException  
  146.      */  
  147.     public static void send(String url, Map<String,String> map,final String encoding, final AsyncHandler handler) throws KeyManagementException, NoSuchAlgorithmException, ClientProtocolException, IOException {  
  148.   
  149.         //绕过证书验证,处理https请求  
  150.         SSLContext sslcontext = createIgnoreVerifySSL();  
  151.           
  152.         // 设置协议http和https对应的处理socket链接工厂的对象  
  153.         Registry<SchemeIOSessionStrategy> sessionStrategyRegistry = RegistryBuilder.<SchemeIOSessionStrategy>create()  
  154.                 .register("http", NoopIOSessionStrategy.INSTANCE)  
  155.                 .register("https"new SSLIOSessionStrategy(sslcontext))  
  156.                 .build();  
  157.         //配置io线程  
  158.         IOReactorConfig ioReactorConfig = IOReactorConfig.custom().setIoThreadCount(Runtime.getRuntime().availableProcessors()).build();  
  159.         //设置连接池大小  
  160.         ConnectingIOReactor ioReactor;  
  161.         ioReactor = new DefaultConnectingIOReactor(ioReactorConfig);  
  162.         PoolingNHttpClientConnectionManager connManager = new PoolingNHttpClientConnectionManager(ioReactor, null, sessionStrategyRegistry, null);  
  163.           
  164.         //创建自定义的httpclient对象  
  165.         final CloseableHttpAsyncClient client = proxy("127.0.0.1"8087).setConnectionManager(connManager).build();  
  166. //      CloseableHttpAsyncClient client = HttpAsyncClients.createDefault();  
  167.           
  168.         //创建post方式请求对象  
  169.         HttpPost httpPost = new HttpPost(url);  
  170.           
  171.         //装填参数  
  172.         List<NameValuePair> nvps = new ArrayList<NameValuePair>();  
  173.         if(map!=null){  
  174.             for (Entry<String, String> entry : map.entrySet()) {  
  175.                 nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));  
  176.             }  
  177.         }  
  178.         //设置参数到请求对象中  
  179.         httpPost.setEntity(new UrlEncodedFormEntity(nvps, encoding));  
  180.   
  181.         System.out.println("请求地址:"+url);  
  182.         System.out.println("请求参数:"+nvps.toString());  
  183.           
  184.         //设置header信息  
  185.         //指定报文头【Content-type】、【User-Agent】  
  186.         httpPost.setHeader("Content-type""application/x-www-form-urlencoded");  
  187.         httpPost.setHeader("User-Agent""Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");  
  188.           
  189.         // Start the client  
  190.         client.start();  
  191.         //执行请求操作,并拿到结果(异步)  
  192.         client.execute(httpPost, new FutureCallback<HttpResponse>() {  
  193.               
  194.             @Override  
  195.             public void failed(Exception ex) {  
  196.                 handler.failed(ex);  
  197.                 close(client);  
  198.             }  
  199.               
  200.             @Override  
  201.             public void completed(HttpResponse resp) {  
  202.                 String body="";  
  203.                 //这里使用EntityUtils.toString()方式时会大概率报错,原因:未接受完毕,链接已关  
  204.                 try {  
  205.                     HttpEntity entity = resp.getEntity();  
  206.                     if (entity != null) {  
  207.                         final InputStream instream = entity.getContent();  
  208.                         try {  
  209.                             final StringBuilder sb = new StringBuilder();  
  210.                             final char[] tmp = new char[1024];  
  211.                             final Reader reader = new InputStreamReader(instream,encoding);  
  212.                             int l;  
  213.                             while ((l = reader.read(tmp)) != -1) {  
  214.                                 sb.append(tmp, 0, l);  
  215.                             }  
  216.                             body = sb.toString();  
  217.                         } finally {  
  218.                             instream.close();  
  219.                             EntityUtils.consume(entity);  
  220.                         }  
  221.                     }  
  222.                 } catch (ParseException | IOException e) {  
  223.                     e.printStackTrace();  
  224.                 }  
  225.                 handler.completed(body);  
  226.                 close(client);  
  227.             }  
  228.               
  229.             @Override  
  230.             public void cancelled() {  
  231.                 handler.cancelled();  
  232.                 close(client);  
  233.             }  
  234.         });  
  235.     }  
  236.       
  237.     /** 
  238.      * 关闭client对象 
  239.      *  
  240.      * @param client 
  241.      */  
  242.     private static void close(CloseableHttpAsyncClient client) {  
  243.         try {  
  244.             client.close();  
  245.         } catch (IOException e) {  
  246.             e.printStackTrace();  
  247.         }  
  248.     }  
  249.       
  250.     static class AsyncHandler implements IHandler{  
  251.           
  252.         @Override  
  253.         public Object failed(Exception e) {  
  254.             System.err.println(Thread.currentThread().getName()+"--失败了--"+e.getClass().getName()+"--"+e.getMessage());  
  255.             return null;  
  256.         }  
  257.         @Override  
  258.         public Object completed(String respBody) {  
  259.             System.out.println(Thread.currentThread().getName()+"--获取内容:"+respBody);  
  260.             return null;  
  261.         }  
  262.         @Override  
  263.         public Object cancelled() {  
  264.             System.out.println(Thread.currentThread().getName()+"--取消了");  
  265.             return null;  
  266.         }  
  267.     }  
  268.       
  269.     /** 
  270.      * 回调处理接口 
  271.      *  
  272.      * @author arron 
  273.      * @date 2015年11月10日 上午10:05:40  
  274.      * @version 1.0 
  275.      */  
  276.     public interface IHandler {  
  277.           
  278.         /** 
  279.          * 处理异常时,执行该方法 
  280.          * @return 
  281.          */  
  282.         Object failed(Exception e);  
  283.           
  284.         /** 
  285.          * 处理正常时,执行该方法 
  286.          * @return 
  287.          */  
  288.         Object completed(String respBody);  
  289.           
  290.         /** 
  291.          * 处理取消时,执行该方法 
  292.          * @return 
  293.          */  
  294.         Object cancelled();  
  295.     }  
  296.       
  297. }  
来一个测试类:
[java]  view plain  copy
 print ?
  1. public static void main(String[] args) throws KeyManagementException, NoSuchAlgorithmException, ClientProtocolException, IOException {  
  2.     AsyncHandler handler = new AsyncHandler();  
  3.     String url = "http://php.weather.sina.com.cn/iframe/index/w_cl.php";  
  4.     Map<String, String> map = new HashMap<String, String>();  
  5.     map.put("code""js");  
  6.     map.put("day""0");  
  7.     map.put("city""上海");  
  8.     map.put("dfc""1");  
  9.     map.put("charset""utf-8");  
  10.     send(url, map, "utf-8", handler);  
  11.       
  12.     System.out.println("-----------------------------------");  
  13.       
  14.     map.put("city""北京");  
  15.     send(url, map, "utf-8", handler);  
  16.       
  17.     System.out.println("-----------------------------------");  
  18.       
  19. }  
测试结果如下:

很简单吧,其实基于HttpAsyncClient的工具类我也进行了封装,跟HttpClient工具类差不多。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值