通用HttpClientUtils工具类,开箱即用

152 阅读1分钟

一、前言

一说到HttpClient大家都有各种方式,网上也都有各种demo;总结网上加上自己实践的,附下面一个通用httpClientUtils类;平时记录住,开发项目用到时,之间cv操作;

image.png

二、依赖


<dependency>
  <groupId>org.apache.httpcomponents</groupId>
  <artifactId>httpclient</artifactId>
  <version>4.5.10</version>
</dependency>

三、源码


public final class HttpClientUtils {
    


    public static  String url = "xxxxx";

    private static PoolingHttpClientConnectionManager manager;
    private static String EMPTY_STR = "";
    private static String UTF_8 = "UTF-8";

   


    private static void init(){
        if (manager == null){
            manager = new PoolingHttpClientConnectionManager();
            //整个链接池最大连接数
            manager.setMaxTotal(50);
            //每个路由最大连接数
            manager.setDefaultMaxPerRoute(5);
            
        }
    }

    /**
     * 通过连接池获取httpClient
     * @return
     */
    private static CloseableHttpClient getHttpClient(){
        init();
        return HttpClients.custom().setConnectionManager(manager).build();
    }

    /**
     * @param url
     * @return
     */
    public static String getHttpRequest(String url) {
        HttpGet httpGet = new HttpGet(url);
        return getResult(httpGet);
    }


    public static String getHttpRequest(String url, Map<String, Object> params) throws URISyntaxException {
        URIBuilder ub = new URIBuilder(url);
        ArrayList<NameValuePair> pairs = covertParams2NVPS(params);
        ub.setParameters(pairs);
        HttpGet httpGet = new HttpGet(ub.build());
        return getResult(httpGet);
    }

    public static String getHttpRequest(String url, Map<String, Object> headers, Map<String, Object> params)
            throws URISyntaxException {
        URIBuilder ub = new URIBuilder();
        ub.setPath(url);
        ArrayList<NameValuePair> pairs = covertParams2NVPS(params);
        ub.setParameters(pairs);
        HttpGet httpGet = new HttpGet(ub.build());
        for (Map.Entry<String, Object> param : headers.entrySet()) {
            httpGet.addHeader(param.getKey(), String.valueOf(param.getValue()));
        }
        return getResult(httpGet);
    }

    public static String postHttpRequest(String url) {
        HttpPost httpPost = new HttpPost(url);
        return getResult(httpPost);
    }

    public static String postHttpRequest(String url,String json) {
        HttpPost httpPost = new HttpPost(url);
        StringEntity entity = new StringEntity(json,"utf-8");//解决中文乱码问题
        entity.setContentEncoding("UTF-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        return getResult(httpPost);
    }

    public static String postHttpRequest(String url, Map<String, Object> params) throws UnsupportedEncodingException {

        HttpPost httpPost = new HttpPost(url);
        ArrayList<NameValuePair> pairs = covertParams2NVPS(params);
        // 配置请求的超时设置
        int timeout=1000*10;
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectionRequestTimeout(timeout)
                .setConnectTimeout(timeout)
                .setSocketTimeout(timeout)
                .build();
        httpPost.setEntity(new UrlEncodedFormEntity(pairs, UTF_8));
        httpPost.setConfig(requestConfig);
        return getResult(httpPost);
    }


    public static String postHttpRequest(String url, Map<String, Object> headers, Map<String, Object> params)
            throws UnsupportedEncodingException {
        HttpPost httpPost = new HttpPost(url);
        for (Map.Entry<String, Object> param : headers.entrySet()) {
            httpPost.addHeader(param.getKey(), String.valueOf(param.getValue()));
        }
        ArrayList<NameValuePair> pairs = covertParams2NVPS(params);
        httpPost.setEntity(new UrlEncodedFormEntity(pairs, UTF_8));

        return getResult(httpPost);
    }

    private static ArrayList<NameValuePair> covertParams2NVPS(Map<String, Object> params) {
        ArrayList<NameValuePair> pairs = new ArrayList<NameValuePair>();
        for (Map.Entry<String, Object> param : params.entrySet()) {
            pairs.add(new BasicNameValuePair(param.getKey(), String.valueOf(param.getValue())));
        }
        return pairs;
    }


    /**
     * 处理http请求
     * @param request
     * @return
     */
    private static String getResult(HttpRequestBase request) {
        CloseableHttpClient httpClient = getHttpClient();
        try {

            System.out.println("");
            CloseableHttpResponse response = httpClient.execute(request);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                String result = EntityUtils.toString(entity);
                response.close();
                return result;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return EMPTY_STR;
    }

    public static void main(String[] args) throws UnsupportedEncodingException {
        long startTime =  System.currentTimeMillis();
        Map<String,Object> param = new HashMap<>();
        param.put("bizCode","xxx");
        param.put("time","xxx");
        param.put("pageNum","1");
        param.put("pageSize","20");
        String result = HttpClientUtils.postHttpRequest(url,param);
        long endTime =  System.currentTimeMillis();
        System.out.println(result);
        System.out.println("耗时:"+ (endTime-startTime)/1000+"秒" );

    }

}

HTTPClient 连接池常见问题

  1. 如何判断连接是否可以保持?

检查返回response报文头的Transfer-Encoding字段,若该字段值存在且不为chunked,则连接不保持,直接关闭。
检查返回的response报文头的Content-Length字段,若该字段值为空或者格式不正确(多个长度,值不是整数),则连接不保持,直接关闭。
检查返回的response报文头的Connection字段(若该字段不存在,则为Proxy-Connection字段)值:
如果这俩字段都不存在,则1.1版本默认为保持, 1.0版本默认为连接不保持,直接关闭。
如果字段存在,若字段值为close 则连接不保持,直接关闭;若字段值为keep-alive则连接标记为保持。

  1. 保持多长时间?

保持时间计时开始时间为连接交换至连接池的时间。 保持时长计算规则为:获取response中 Keep-Alive字段中timeout值,若该存在,则保持时间为 timeout值*1000,单位毫秒。若不存在,则连接保持时间设置为-1,表示为无穷。

  1. 保持过程中如何保证连接没有失效?

很难保证。传统阻塞I/O模型,只有当I/O操做的时候,socket才能响应I/O事件。当TCP连接交给连接管理器后,它可能还处于“保持连接”的状态,但是无法监听socket状态和响应I/O事件。如果这时服务器将连接关闭的话,客户端是没法知道这个状态变化的,从而也无法采取适当的手段来关闭连接。

针对这种情况,HttpClient采取一个策略,通过一个后台的监控线程定时的去检查连接池中连接是否还“新鲜”,如果过期了,或者空闲了一定时间则就将其从连接池里删除掉。ClientConnectionManager提供了 closeExpiredConnections和closeIdleConnections两个方法。

备注:参考github.com/Arronlong/h…