HTTP请求异步编程解决堵塞之痛-Apache HttpClient5.0

5e8c59d21335da2835320f16264c37c4.png

序言

        相信很多同学用过  Apache HttpClient 组件进行过 http请求,尤其是对第三方系统的http  api  进行调用。在spring cloud 大行其道的今天,微服务之间通过http协议进行调用的场景应用越来越多,今天大黄鸭就 Apache HttpClient5.0的同步、异步、fluent风格、cache插件的使用写个demo,希望可以帮到需要的同学。

一、maven坐标引入

<dependency>


   <groupId>org.apache.httpcomponents.client5</groupId>


   <artifactId>httpclient5</artifactId>


   <version>5.0.3</version>


</dependency>


<dependency>


   <groupId>org.apache.httpcomponents.client5</groupId>


   <artifactId>httpclient5-fluent</artifactId>


   <version>5.0.3</version>


</dependency>


<dependency>


   <groupId>org.apache.httpcomponents.client5</groupId>


   <artifactId>httpclient5-cache</artifactId>


   <version>5.0.3</version>


</dependency>

二、经典的堵塞式编程

/**


* @Description HttpClient用法演示


* @Author lvaolin


* @Date 2021/2/9 4:07 下午


*/


public class HttpClientClassic {


   public static void main(String[] args) throws IOException, ParseException {


       //关于CloseableHttpClient实例的创建HttpClients提供了多种方式,高级用法可以使用定制方法 HttpClients.custom()


       try (CloseableHttpClient httpclient = HttpClients.createDefault()) {


           //创建一个get类型的http请求


           HttpGet httpGet = new HttpGet("http://www.baidu.com/");


           try (CloseableHttpResponse response1 = httpclient.execute(httpGet)) {


               System.out.println(response1.getCode() + " " + response1.getReasonPhrase());


               HttpEntity entity1 = response1.getEntity();


               EntityUtils.consume(entity1);


           }


           //创建一个post类型的http请求


           HttpPost httpPost = new HttpPost("http://www.baidu.com/");


           List<NameValuePair> nvps = new ArrayList<>();


           nvps.add(new BasicNameValuePair("username", "aaa"));


           nvps.add(new BasicNameValuePair("password", "12345"));


           //这是一个form表单类型的数据格式,放入request body中


           httpPost.setEntity(new UrlEncodedFormEntity(nvps,Charsets.UTF_8));


           //如果是json格式,如下处理,统一使用 UTF-8 可以避免 客户端与服务器端编码不一致问题


           //httpPost.setEntity(new StringEntity("{}",Charsets.UTF_8));


           try (CloseableHttpResponse response2 = httpclient.execute(httpPost)) {


               //响应编码 以及 原因, 比如: 502 Bad Gateway


               System.out.println(response2.getCode() + " " + response2.getReasonPhrase());


               HttpEntity entity2 = response2.getEntity();


               //将响应流转为字符串形式,你可以自己根据需要使用EntityUtils工具进行处理,当然也可以自己解析 InputStream 流


               String stringBody = EntityUtils.toString(entity2, Charsets.UTF_8);


               //简单打印下


               System.out.println(stringBody);


               //确保关闭流资源


               EntityUtils.consume(entity2);


           }


       }


   }


}

三、异步编程

/**


* @Description http client 异步编程


* @Author lvaolin


* @Date 2021/2/9 4:40 下午


*/


public class HttpClientAsync {


   public static void main(String[] args) throws IOException, ExecutionException, InterruptedException {


       //CloseableHttpAsyncClient的实例创建同样也有多种方式,高级用法就是用HttpAsyncClients.custom() 定制自己的参数


       try (CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault()) {


           //这句话是异步编程api 独有的


           httpclient.start();


           //-----1、 下面是第一种用法--通过获取Future句柄来灵活控制逻辑---


           //执行一个get请求


           SimpleHttpRequest request10 = SimpleHttpRequests.get("http://www.baidu.com/");


           SimpleHttpRequest request11 = SimpleHttpRequests.get("https://yonyou.com/");


           //下面这2步是关键,非堵塞的,返回 future句柄


           Future<SimpleHttpResponse> future10 = httpclient.execute(request10, null);


           Future<SimpleHttpResponse> future11 = httpclient.execute(request11, null);


           //等待响应返回


           SimpleHttpResponse response10 = future10.get();


           System.out.println(response10.getBodyText());


           SimpleHttpResponse response11 = future11.get();


           //-----2、 下面是第二种用法--通过FutureCallback 来实现理想中的异步回调 ---


           //CountDownLatch 是否使用 取决于你的业务需要,


           //你如果想在它回调完成时 再去做一些事情,就可以用 CountDownLatch来控制,否则就可以去掉CountDownLatch的代码


           final CountDownLatch latch1 = new CountDownLatch(1);


           final SimpleHttpRequest request2 = SimpleHttpRequests.get("http://www.baidu.com/");


           httpclient.execute(request2, new FutureCallback<SimpleHttpResponse>() {


               @Override


               public void completed(SimpleHttpResponse response2) {


                   latch1.countDown();


                   System.out.println(request2.getRequestUri() + "->" + response2.getCode());


               }


               @Override


               public void failed(Exception ex) {


                   latch1.countDown();


                   System.out.println(request2.getRequestUri() + "->" + ex);


               }


               @Override


               public void cancelled() {


                   latch1.countDown();


                   System.out.println(request2.getRequestUri() + " cancelled");


               }


           });


           latch1.await();


       }


   }


}

四、fluent风格编程

public class HttpClientFluent {


   public static void main(String[] args) throws IOException {


       //这种风格的编程确实很简洁清晰,给人流畅的感觉------


       Content content = Request.get("http://www.baidu.com/")


               .setHeader("Connection","keep-alive")


               .execute()


               .returnContent();


       System.out.println(content.asString());


       Content content2 = Request.post("http://www.baidu.com/")


               .setHeader("Connection","keep-alive")


               .setHeader("Accept", "application/json")


               .setHeader("Content-Type", "application/json")//设置header信息


               .bodyByteArray("{  }".getBytes(Charsets.UTF_8))//发送json格式的数据


               .execute()


               .returnContent();


       System.out.println(content2.asString());


   }


}

五、脱离了浏览器如何缓存http 静态资源信息

/**


* @Description HttpClientCache插件的用途


* @Author lvaolin


* @Date 2021/2/9 3:36 下午


*/


public class HttpClientCache {


   public static void main(String[] args) throws IOException {


       CacheConfig cacheConfig = CacheConfig.custom()


               .setMaxCacheEntries(1000)


               .setMaxObjectSize(8192)


               .build();


       RequestConfig requestConfig = RequestConfig.custom()


               .setConnectTimeout(3, TimeUnit.SECONDS)


               .setConnectionRequestTimeout(10, TimeUnit.SECONDS)


               .build();


       CloseableHttpClient cachingClient = CachingHttpClients.custom()


               .setCacheConfig(cacheConfig)


               .setDefaultRequestConfig(requestConfig)


               .build();


       HttpCacheContext context = HttpCacheContext.create();


       HttpGet httpget = new HttpGet("http://www.baidu.com/");


       for (int i = 0; i <3 ; i++) {


           CloseableHttpResponse response = cachingClient.execute(httpget, context);


           try {


               CacheResponseStatus responseStatus = context.getCacheResponseStatus();


               switch (responseStatus) {


                   case CACHE_HIT:


                       System.out.println("A response was generated from the cache with " +


                               "no requests sent upstream");


                       break;


                   case CACHE_MODULE_RESPONSE:


                       System.out.println("The response was generated directly by the " +


                               "caching module");


                       break;


                   case CACHE_MISS:


                       System.out.println("The response came from an upstream server");


                       break;


                   case VALIDATED:


                       System.out.println("The response was generated from the cache " +


                               "after validating the entry with the origin server");


                       break;


               }


           } finally {


               response.close();


           }


       }


       cachingClient.close(CloseMode.GRACEFUL);


   }


}

六、总结

         在合适的场景使用异步编程能很好的提高程序的性能,打个比喻就是 你在蒸米饭的同时可以去炒菜,还可以同时去烧水,三件事情并行执行,花费的总时间就是最耗时的那个活,如果是堵塞式串行执行,那么花费总时间就是三件事情的时间之和,有没有运筹学的味道在里面。

        fluent风格编程确实清晰易懂简洁流畅,有兴趣的同学可以学习这种风格。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
作为一个AI语言模型,我无法提供wechatpay-apache-httpclient的完整用例,但我可以为您提供一些参考资料和建议: 1. 我们可以在官方文档中找到wechatpay-apache-httpclient的使用方法。可以参考https://wechatpay-api.gitbook.io/wechatpay-api-v3/chang-jian-wen-ti/httpclient-ru-he-shi-yong 2. 首先,需要在项目中引入wechatpay-apache-httpclient的依赖,例如在Maven项目中,可以在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>com.wechatpay</groupId> <artifactId>wechatpay-apache-httpclient</artifactId> <version>6.5.6</version> </dependency> ``` 3. 接下来,我们需要配置httpClient,包括设置连接池、连接超时时间、读取超时时间等。例如: ```java PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(); connectionManager.setMaxTotal(100); // 最大连接数 connectionManager.setDefaultMaxPerRoute(20); // 单个路由最大连接数 RequestConfig requestConfig = RequestConfig.custom() .setConnectTimeout(5000) // 连接超时时间 .setSocketTimeout(5000) // 读取超时时间 .build(); CloseableHttpClient httpClient = HttpClients.custom() .setConnectionManager(connectionManager) .setDefaultRequestConfig(requestConfig) .build(); ``` 4. 然后,我们可以使用httpClient发送请求,并处理响应结果。例如: ```java HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi"); httpPost.setHeader("Content-Type", "application/json"); httpPost.setHeader("Accept", "application/json"); httpPost.setHeader("Wechatpay-Serial", "XXXXXXXXXXX"); httpPost.setHeader("Authorization", "WECHATPAY2-SHA256-RSA2048 " + accessToken); StringEntity entity = new StringEntity(requestJson, "UTF-8"); httpPost.setEntity(entity); HttpResponse httpResponse = httpClient.execute(httpPost); int statusCode = httpResponse.getStatusLine().getStatusCode(); String responseJson = EntityUtils.toString(httpResponse.getEntity(), "UTF-8"); if (statusCode == HttpStatus.SC_OK) { // 处理成功响应结果 } else { // 处理失败响应结果 } ``` 以上代码仅为示例,具体使用方法还需根据实际情况进行调整。同时,为了保证代码的可读性和可维护性,建议使用封装好的工具类来处理httpClient请求和响应结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吕哥架构

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值