HttpClient使用教程

一、 背景

1、原生的的java.net.HttpURLConnection并不支持连接池,使用便捷性不好。

2、用 HttpURLConnection 发送json数据的教程如下:

 /**
     * 发送 json 数据的 post 请求
     * @param json 数据内容
     * @return 响应结果
     */
    private String doJsonPost(String json) throws IOException {

        URL url = new URL(String.format("http://%s:%d/api/v1/alerts", this.amHost, this.amPort));

        HttpURLConnection conn = (HttpURLConnection) url.openConnection();

        // HttpClient 6.0被抛弃了
        String result = "";
        BufferedReader reader = null;
        try {

            conn.setRequestMethod("POST");
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            conn.setRequestProperty("Connection", "Keep-Alive");
            conn.setRequestProperty("Charset", "UTF-8");
            // 设置文件类型:
            conn.setRequestProperty("Content-Type","application/json; charset=UTF-8");
            // 设置接收类型否则返回415错误
            //conn.setRequestProperty("accept","*/*")此处为暴力方法设置接受所有类型,以此来防范返回415;
            conn.setRequestProperty("accept","application/json");
            // 往服务器里面发送数据
            if (json != null && !TextUtils.isEmpty(json)) {
                byte[] writebytes = json.getBytes();
                // 设置文件长度
                conn.setRequestProperty("Content-Length", String.valueOf(writebytes.length));
                OutputStream outwritestream = conn.getOutputStream();
                outwritestream.write(json.getBytes());
                outwritestream.flush();
                outwritestream.close();
                log.info("doJsonPost: {}", conn.getResponseCode());
            }
            if (conn.getResponseCode() == 200) {
                reader = new BufferedReader( new InputStreamReader(conn.getInputStream()));
                result = reader.readLine();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

二、HttpClient 使用

1、HttpClient 通过连接池创建连接

1、管理连接的基本单位是Route(路由),每个路由上都会维护一定数量的HTTP连接:
2、每次调用后必须执行 releaseConnection
3、路由可以理解为客户端机器到目标机器的一条线路
4、如果不给 httpclient配置指定的连接管理器,httpclient会自动使用PoolingHttpClientConnectionManager作为连接管理器。
5、PoolingHttpClientConnectionManager默认的maxConnPerRoute和maxConnTotal分别是是2和20。
6、也就是对于每个服务器最多只会维护2个连接,看起来有点少。所以,在日常使用时我们尽量使用自己配置的连接管理器比较好。

2、扩展

  • 连接池

1、连接池技术作为创建和管理连接的缓冲池技术。
2、连接池管理的对象是长连接
3、有长连接的优势

  • 长连接:是指客户端与服务器端一旦建立连接以后,可以进行多次数据传输而不需重新建立连接,
    优势:1、省去了每次数据传输连接建立的时间开销,2、资源的访问控制

  • 短连接:每次数据传输都需要客户端和服务器端建立一次连接

3、使用教程

package com.util;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;

import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * HttpClient 工具类
 */
@Slf4j
public class HttpClientUtil {
    public static final String APPLICATION_JSON_VALUE = "application/json";
    private static final Logger logger = log;
    private static final Integer CONN_TIME_OUT = 3000;// 超时时间豪秒
    private static final Integer SOCKET_TIME_OUT = 10000;

    /** 每个路由的最大请求数,默认2 */
    private static final Integer DEFAULT_MAX_PER_ROUTE = 40;

    /** 最大连接数,默认20 */
    private static final Integer MAX_TOTAL = 400;


    private static HttpClient httpClient;

    static {
        // 请求配置
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(CONN_TIME_OUT)
                .setConnectionRequestTimeout(CONN_TIME_OUT)
                .setSocketTimeout(SOCKET_TIME_OUT)
                .build();

        // 管理 http连接池
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
        cm.setDefaultMaxPerRoute(DEFAULT_MAX_PER_ROUTE);
        cm.setMaxTotal(MAX_TOTAL);

        httpClient = HttpClients.custom().setConnectionManager(cm).setDefaultRequestConfig(requestConfig).build();
    }

    public static String requestGet(String url, Map<String, String> paramsMap) throws Exception {
        logger.info("GET request  url:{} params:{}", url, paramsMap);

        Long start = System.currentTimeMillis();

        List<NameValuePair> params = initParams(paramsMap);
        // Get请求
        HttpGet httpGet = new HttpGet(url);

        try {
            // 设置参数
            String str = EntityUtils.toString(new UrlEncodedFormEntity(params, StandardCharsets.UTF_8));
            String uriStr = StringUtils.isEmpty(str) ? httpGet.getURI().toString() : httpGet.getURI().toString() + "?" + str;
            httpGet.setURI(new URI(uriStr));
            // 发送请求
            HttpResponse response = httpClient.execute(httpGet);
            logger.info("GET request  url:{} response:{} time:{}",
                    url, response, System.currentTimeMillis() - start);

            // 获取返回数据
            return getSuccessRetFromResp(response, url, JSON.toJSONString(paramsMap));
        } finally {
            // 必须释放连接,负责连接用完后会阻塞
            httpGet.releaseConnection();
        }
    }

    /**
     *
     * @param url
     * @param paramsMap
     * @return 响应结果
     */
    public static String requestPost(String url, Map<String, String> paramsMap) throws Exception {
        logger.info("POST request  url:{} params:{}", url, paramsMap);
        Long start = System.currentTimeMillis();

        List<NameValuePair> params = initParams(paramsMap);

        HttpPost httpPost = new HttpPost(url);

        try {

            httpPost.setEntity(new UrlEncodedFormEntity(params, Consts.UTF_8));

            HttpResponse response = httpClient.execute(httpPost);

            logger.info("POST request  url:{} response:{}  time:{}",
                    url, response, System.currentTimeMillis() - start);

            String retStr = getSuccessRetFromResp(response, url, JSON.toJSONString(paramsMap));


            return retStr;
        } finally {
            httpPost.releaseConnection();
        }
    }

    /**
     * POST json 格式数据
     *
     */
    public static String requestPostJsonStr(String url, String json) throws Exception {

        logger.info("POST request  url:{} params:{}", url, json);

        long start = System.currentTimeMillis();

        HttpPost httpPost = new HttpPost(url);

        try {
            StringEntity entity = new StringEntity(json, Consts.UTF_8);
            entity.setContentType(APPLICATION_JSON_VALUE);

            httpPost.setEntity(entity);

            HttpResponse response = httpClient.execute(httpPost);

            logger.info("POST request  url:{} response:{}  time:{}", url, response, System.currentTimeMillis() - start);

            return getSuccessRetFromResp(response, url, json);
        } finally {
            // 资源释放
            httpPost.releaseConnection();
        }

    }

    /**
     * post json 格式数据
     *
     * @param url
     * @param obj
     * @return
     * @throws Exception
     */
    public static String requestPostJson(String url, Object obj) throws Exception {
        String params = JSON.toJSONString(obj);
        return requestPostJsonStr(url, params);
    }

    private static String getSuccessRetFromResp(HttpResponse response, String url, String params) throws Exception {
        String retStr = "";
        // 检验状态码,如果成功接收数据
        int code = response.getStatusLine().getStatusCode();

        if (code == 200) {
            retStr = EntityUtils.toString(response.getEntity(), Consts.UTF_8);
        } else {
            throw new RuntimeException(String.format("Http request error:%s, url:%s, params:%s", response, url, params));
        }

        logger.info("Http request retStr:{}. url:{}", retStr, url);
        return retStr;
    }

    private static List<NameValuePair> initParams(Map<String, String> paramsMap) {

        List<NameValuePair> params = new ArrayList<NameValuePair>();
        if (paramsMap == null)
            return params;

        for (Map.Entry<String, String> entry : paramsMap.entrySet()) {
            params.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
        }

        return params;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值