HttpClient异步请求

pom依赖

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.6.2</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.13</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.62</version>
        </dependency>

        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpcore</artifactId>
            <version>4.4.15</version>
        </dependency>

        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpcore-nio</artifactId>
            <version>4.4.14</version>
        </dependency>

<!--        <dependency>-->
<!--            <groupId>org.apache.httpcomponents</groupId>-->
<!--            <artifactId>httpasyncclient</artifactId>-->
<!--            <version>4.1.2</version>-->
<!--        </dependency>-->

        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpasyncclient</artifactId>
            <version>4.1.1</version>
        </dependency>

工具类代码

package com.mt.utils;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
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.nio.reactor.ConnectingIOReactor;
import org.apache.http.nio.reactor.IOReactorException;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;

/**
 * author: 15aaa2
 * description: client异步请求工具类
 * date: 2022/1/5 14:04
 */
public class HttpClientUtils {

    private static final CountDownLatch LATCH = new CountDownLatch(1);

    private static final Logger LOGGER = Logger.getLogger(HttpClientUtils.class);


    /**
     * get请求
     * @param path 路径
     * @param params 参数集合
     * @return 返回结果
     */
    public static String getRequest(String path, List<NameValuePair> params){
        if (path.isEmpty()){
            LOGGER.error("path can not be null");
            return null;
        }
        CloseableHttpAsyncClient client = null;
        HttpGet get = null;
        try {
            client = newHttpClient();
            client.start();
            URIBuilder uri = new URIBuilder(path);
            if (!CollectionUtils.isEmpty(params)){
                uri.setParameters(params);
            }
            get = new HttpGet(uri.build());

            Future<HttpResponse> execute = client.execute(get, new Back(LATCH));
            HttpResponse response = execute.get();
            HttpEntity entity = response.getEntity();
//            String s = EntityUtils.toString(entity);
//            System.out.println("==========");
//            System.out.println(s);
//            System.out.println("==========");
            return EntityUtils.toString(entity);

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (get != null){
                get.releaseConnection();
            }
            if (client!=null){
                try {
                    client.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return null;
    }


    /**
     * post请求
     * @param path 路径
     * @param entity JSON对象参数
     * @param params 普通参数
     * @return 返回结果
     */
    public static String postRequest(String path, StringEntity entity,List<NameValuePair> params){
        CloseableHttpAsyncClient client = null;
        HttpPost post = null;
        try {
            client = newHttpClient();
            client.start();

            URIBuilder uri = new URIBuilder(path);
            if (!CollectionUtils.isEmpty(params)){
                uri.setParameters(params);
            }
            post = new HttpPost(uri.build());
            post.addHeader("Content-Type", "application/json");
            post.addHeader("Accept", "application/json");
            if (entity != null){
                post.setEntity(entity);
            }
            Future<HttpResponse> execute = client.execute(post, new Back(LATCH));
            HttpResponse response = execute.get();
            if (response.getStatusLine().getStatusCode() != 200){
                System.out.println("请求失败");
                return null;
            }
            return EntityUtils.toString(response.getEntity());
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (post!=null){
                post.releaseConnection();
            }
            if (client!=null){
                try {
                    client.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    /**
     * 创建httpClient实例
     * @return 返回CloseableHttpAsyncClient
     */
    private static CloseableHttpAsyncClient newHttpClient(){
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(50000)
                .setSocketTimeout(50000)
                .setConnectionRequestTimeout(1000)
                .build();

        //配置io线程
        IOReactorConfig ioReactorConfig = IOReactorConfig.custom().
                setIoThreadCount(Runtime.getRuntime().availableProcessors())
                .setSoKeepAlive(true)
                .build();
        //设置连接池大小
        ConnectingIOReactor ioReactor=null;
        try {
            ioReactor = new DefaultConnectingIOReactor(ioReactorConfig);
        } catch (IOReactorException e) {
            e.printStackTrace();
        }
        PoolingNHttpClientConnectionManager connManager = new PoolingNHttpClientConnectionManager(ioReactor);
        connManager.setMaxTotal(100);
        connManager.setDefaultMaxPerRoute(100);

        CloseableHttpAsyncClient client = HttpAsyncClients.custom().
                setConnectionManager(connManager)
                .setDefaultRequestConfig(requestConfig)
                .build();

        return client;
    }


    static class Back implements FutureCallback<HttpResponse>{

        private CountDownLatch countDownLatch;

        Back(CountDownLatch countDownLatch){
            this.countDownLatch = countDownLatch;
        }

        @Override
        public void completed(HttpResponse result) {
//            System.out.println("-------------");
//            System.out.println(result.getEntity());
//            System.out.println("-------------");
            LATCH.countDown();
        }

        @Override
        public void failed(Exception ex) {
            LATCH.countDown();
        }

        @Override
        public void cancelled() {
            LATCH.countDown();
        }
    }
}

一个工作时写的工具包。实现了Java版的Promise 和 HttpClientHttpClient 支持同步和异步两种方式,也支持多种不同实现。目前有Netty 和 Apache Compoenet两种实现。本次上传移除了Netty实现。主要解决生产环境中同步httpclient造成的IO阻塞问题。同步http请求将导致 tomcat 的业务线程被阻塞。一旦某接口网络出现问题,可能会阻塞tomcat业务线程,从而无法处理正常业务。很多公司使用另开线程池的方式进行异步调用来解决tomcat线程阻塞问题。但由于本系统中接口网络太不稳定,使用线程池也将导致线程池中的线程不断加大,不管使用怎样的线程池策略,最终要么线程池线程全部挂起,要么部分任务被延迟执行,要么丢失部分任务。这在我们的系统中仍然不能接受。因此才有了这个组件的开发。该组件是单线程非阻塞式的,类似于JS中的ajax请求。都使用单线程异步回调的方式。目前该组件已经初步测试通过。如果大家也需要这样的组件,可以下载尝试一下。所有关键注释都已经写了,如有不明白可以发送邮件 ath.qu.trues@gmail.com 代码分为3个maven模块。 commons-ext : 实现Promise commons-tools: 实现 异步httpclient commons-parent:父模块 测试代码在 commons-tools/src/test/java/HttpTest.java 中. 要求至少Java 8 版本。 注释已经写好。这里贴出异步的http部分测试代码。 /** * 异步方法的Fluent写法 */ public void testAsyncHttpFluent() { SimpleRequest.Get("http://www.baidu.com") .header("h1", "hv1") .header("h2", "hv2") .parameter("p1", "pv1") .parameter("p2", "pv2") .chartUTF8() .build() .asyncExecute() .then(SimpleAsyncHttpClient::asString) .then(html -> { System.out.println(html); }) .catching(Throwable::printStackTrace);//如果有异常,则打印异常 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值