HTTP 协议的客户端编程工具包HttpClient

HttpClient概述

HttpClient相比传统JDK自带的URLConnection,增加了易用性和灵活性,它不仅使客户端发送Http请求变得容易,而且也方便开发人员测试接口(基于Http协议的),提高了开发的效率,也方便提高代码的健壮性。因此熟练掌握HttpClient是很重要的必修内容,掌握HttpClient后,相信对于Http协议的了解会更加深入。

HttpClient是Apache Jakarta Common下的子项目,用来提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包,并且它支持HTTP协议最新的版本和建议。HttpClient已经应用在很多的项目中,比如Apache Jakarta上很著名的另外两个开源项目Cactus和HTMLUnit都使用了HttpClient。

HttpClient依赖

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.12</version>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpcore</artifactId>
    <version>4.4.13</version>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpmime</artifactId>
    <version>4.5.12</version>
</dependency>

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.32</version>
</dependency>
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.6</version>
</dependency>

HttpClient的创建及配置

创建HttpClient实例

//创建CloseableHttpClient的方式
//方式一
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
//方式二
httpClient = HttpClients.custom().build();

池化管理

关键类:org.apache.http.impl.conn.PoolingHttpClientConnectionManager。 

一般的设置方式:

// 创建连接池管理器
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();

// 创建SocketConfig配置, 主要是建立连接后,通信双方的配置,其实就是我们认识的客户端与服务端的套接字(Socket)通信
SocketConfig socketConfig = SocketConfig.custom()
    .setTcpNoDelay(true)
    .setBacklogSize(1024)
    .setSndBufSize(1000)
    .setRcvBufSize(1000)
    .setSoKeepAlive(true)
    .setSoLinger(100)
    .setSoReuseAddress(true)
    .setSoTimeout(100)
    .build();
connManager.setDefaultSocketConfig(socketConfig);
connManager.setSocketConfig(new HttpHost("localhost", 80), socketConfig);

//检测不活跃连接的有效性时间
connManager.setValidateAfterInactivity(1000);

// 消息报文约束
MessageConstraints messageConstraints = MessageConstraints.custom()
    .setMaxHeaderCount(200)
    .setMaxLineLength(2000)
    .build();

// 创建连接配置
ConnectionConfig connectionConfig = ConnectionConfig.custom()
    .setMalformedInputAction(CodingErrorAction.IGNORE)
    .setUnmappableInputAction(CodingErrorAction.IGNORE)
    .setCharset(Consts.UTF_8)
    .setMessageConstraints(messageConstraints)
    .build();
connManager.setDefaultConnectionConfig(connectionConfig);
connManager.setConnectionConfig(new HttpHost("localhost", 80), ConnectionConfig.DEFAULT);

//配置最大的连接数
connManager.setMaxTotal(100);
//配合路由的最大连接数
connManager.setDefaultMaxPerRoute(10);
connManager.setMaxPerRoute(new HttpRoute(new HttpHost("localhost", 80)), 20);
//创建http客户端
CloseableHttpClient client = HttpClients.custom().setConnectionManager(connManager).build();

SocketConfig配置

  • soTimeout:对应SocketOptions.SO_TIMEOUT参数。单位是毫秒,表示等待客戶端连接的最长时间。
  • soReuseAddress:对应SocketOptions.SO_REUSEADDR参数。是否允许重用服务器所绑定的地址。
  • soLinger:对应SocketOptions.SO_LINGER参数。当调用close socket关闭套接字时,SO_LINGER将决定系统如何处理残存在套接字发送队列中的数据。处理方式无非两种:丢弃或者将数据继续发送至对端,优雅关闭连接。SO_LINGER默认值是-1,表示禁用,即当调用close socket关闭套接字后,将立即返回;如果这时仍然有未被送出的数据包,那么这些数据包将被丢弃。如果将linger参数设为一个正整数n时(n的值最大是65,535) ,在调用close方法后,将最多被阻塞n秒。在这n秒内,系统将尽量将未送出的数据包发送出去;如果超过了n秒,如果还有未发送的数据包,这些数据包将全部被丢弃,而close方法会立即返回。如果将linger设为0 ,和关闭SO_LINGER 选项的作用是一样的。事实上,SO_LINGER并不被推荐使用,大多数情况下我们推荐使用默认的关闭方式即可。
  • soKeepAlive:对应SocketOptions.SO_KEEPALIVE参数。
  • tcpNoDelay:对应SocketOptions.TCP_NODELAY参数。在TCP/IP协议中,无论发送多少数据,总是要在数据前面加上协议头,同时,对方接收到数据,也需要发送ACK表示确认。为了尽可能的利用网络带宽,TCP总是希望尽可能的发送足够大的数据。这里就涉及到一个名为Nagle的算法,该算法的目的就是为了尽可能发送大块数据,避免网络中充斥着许多小数据块。TCP_NODELAY选项,就是用于启用或关于Nagle算法。如果要求高实时性,有数据发送时就马上发送,就将该选项设置为true关闭Nagle算法;如果要减少发送次数减少网络交互,就设置为false等累积一定大小后再发送。
  • sndBufSize:对应SocketOptions.SO_SNDBUF参数。发送数据的缓冲区的大小。
  • rcvBufSize:对应SocketOptions.SO_RCVBUF参数。接收数据的缓冲区的大小。
  • backlogSize:服务端处理线程全忙后,允许多少个新请求进入等待。
// 创建SocketConfig配置, 主要是建立连接后,通信双方的配置,其实就是我们认识的客户端与服务端的套接字(Socket)通信
SocketConfig socketConfig = SocketConfig.custom()
    .setTcpNoDelay(true)
    .setBacklogSize(1024)
    .setSndBufSize(1000)
    .setRcvBufSize(1000)
    .setSoKeepAlive(true)
    .setSoLinger(100)
    .setSoReuseAddress(true)
    .setSoTimeout(100)
    .build();

ConnectionConfig配置

// 消息报文约束
MessageConstraints messageConstraints = MessageConstraints.custom()
    .setMaxHeaderCount(200)
    .setMaxLineLength(2000)
    .build();

// 创建连接配置
ConnectionConfig connectionConfig = ConnectionConfig.custom()
    .setMalformedInputAction(CodingErrorAction.IGNORE)
    .setUnmappableInputAction(CodingErrorAction.IGNORE)
    .setCharset(Consts.UTF_8)
    .setMessageConstraints(messageConstraints)
    .build();

绕过SSL证书

public static void main(String[] args) throws Exception{
    String body = "";

    //采用绕过验证的方式处理https请求
    SSLContext sslcontext = createIgnoreVerifySSL();

    //设置协议http和https对应的处理socket链接工厂的对象
    Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
        .register("http", PlainConnectionSocketFactory.INSTANCE)
        .register("https", new SSLConnectionSocketFactory(sslcontext))
        .build();
    PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
    HttpClients.custom().setConnectionManager(connManager);


    //创建自定义的httpclient对象
    CloseableHttpClient client = HttpClients.custom().setConnectionManager(connManager).build();
    //CloseableHttpClient client = HttpClients.createDefault();

    try {
        //创建get方式请求对象
        HttpGet get = new HttpGet("https://www.baidu.com/");

        //指定报文头Content-type、User-Agent
        get.setHeader("Content-type", "application/x-www-form-urlencoded");
        get.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; rv:6.0.2) Gecko/20100101 Firefox/6.0.2");

        //执行请求操作,并拿到结果(同步阻塞)
        CloseableHttpResponse response = client.execute(get);

        //获取结果实体
        HttpEntity entity = response.getEntity();
        if (entity != null) {
            //按指定编码转换结果实体为String类型
            body = EntityUtils.toString(entity, "UTF-8");
        }

        EntityUtils.consume(entity);
        //释放链接
        response.close();
        System.out.println("body:" + body);
    } finally {
        client.close();
    }
}

public static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {
    SSLContext sc = SSLContext.getInstance("SSLv3");

    // 实现一个X509TrustManager接口,用于绕过验证,不用修改里面的方法
    X509TrustManager trustManager = new X509TrustManager() {
        @Override
        public void checkClientTrusted(
            java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
            String paramString) throws CertificateException {
        }

        @Override
        public void checkServerTrusted(
            java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
            String paramString) throws CertificateException {
        }

        @Override
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    };

    sc.init(null, new TrustManager[]{trustManager}, null);
    return sc;
}

HttpClient请求响应

http请求参数配置 

关键类:org.apache.http.client.config.RequestConfig

httpclient的请求参数主要是通过RequestConfig封装,然后通过httpGet.setConfig(config);把RequestConfig对象传进来

RequestConfig有以下成员变量,基本都有相应的set方法:

private final boolean expectContinueEnabled;
private final HttpHost proxy;
private final InetAddress localAddress;
private final boolean staleConnectionCheckEnabled;
private final String cookieSpec;
private final boolean redirectsEnabled;
private final boolean relativeRedirectsAllowed;
private final boolean circularRedirectsAllowed;
private final int maxRedirects;
private final boolean authenticationEnabled;
private final Collection<String> targetPreferredAuthSchemes;
private final Collection<String> proxyPreferredAuthSchemes;
private final int connectionRequestTimeout;
private final int connectTimeout;
private final int socketTimeout;

例如:

  • setConnectTimeout 设置连接超时时间
  • setConnectionRequestTimeout 设置连接请求最长时间
  • setSocketTimeout 数据传输的最长时间
  • setStaleConnectionCheckEnabled 提交请求前测试连接是否可用 

示例:

// 创建Httpclient对象
CloseableHttpClient httpclient = HttpClients.createDefault();

// 创建http GET请求
HttpGet httpGet = new HttpGet("http://www.baidu.com/");

// 构建请求配置信息
RequestConfig config = RequestConfig.custom().setConnectTimeout(1000) // 创建连接的最长时间
    .setConnectionRequestTimeout(500) // 从连接池中获取到连接的最长时间
    .setSocketTimeout(10 * 1000) // 数据传输的最长时间
    .setStaleConnectionCheckEnabled(true) // 提交请求前测试连接是否可用
    .build();
// 设置请求配置信息
httpGet.setConfig(config);

CloseableHttpResponse response = null;
try {
    // 执行请求
    response = httpclient.execute(httpGet);
    // 判断返回状态是否为200
    if (response.getStatusLine().getStatusCode() == 200) {
        String content = EntityUtils.toString(response.getEntity(), "UTF-8");
        System.out.println(content);
    }
} finally {
    if (response != null) {
        response.close();
    }
    httpclient.close();
}

HttpClient的工具类

import org.apache.http.*;
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.config.ConnectionConfig;
import org.apache.http.config.MessageConstraints;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.ByteArrayBody;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.entity.mime.content.StringBody;
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 java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.SocketTimeoutException;
import java.net.URLEncoder;
import java.nio.charset.CodingErrorAction;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author linhongwei
 * @version 1.0.0
 * @ClassName HttpClientUtil.java
 * @Description http client工具类
 */
@Slf4j
public final class HttpClientUtil {
    /**
     * 默认连接超时时间,单位ms
     */
    public static final int CONNECT_TIME_OUT = 6 * 1000;
    /**
     * 默认读取响应超时时间,单位ms
     */
    public static final int READ_TIME_OUT = 6 * 1000;
    /**
     * 默认字符编码
     */
    public static final String CHARSET = "UTF-8";
    /**
     * 默认mime类型
     */
    public static final String APPLICATION_FORM_URLENCODED_VALUE = "application/x-www-form-urlencoded";
    public static final String APPLICATION_JSON_VALUE = "application/json";
    /**
     * 全局HttpClient
     */
    private static HttpClient client = null;

    static {
        // 创建连接池管理器
        PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();

        // 创建SocketConfig配置, 主要是建立连接后,通信双方的配置,其实就是我们认识的客户端与服务端的套接字(Socket)通信
        SocketConfig socketConfig = SocketConfig.custom()
            .setTcpNoDelay(true)
            .setBacklogSize(1024)
            .setSndBufSize(1000)
            .setRcvBufSize(1000)
            .setSoKeepAlive(true)
            .setSoLinger(100)
            .setSoReuseAddress(true)
            .setSoTimeout(100)
            .build();
        connManager.setDefaultSocketConfig(socketConfig);

        //检测不活跃连接的有效性时间
        connManager.setValidateAfterInactivity(1000);

        // 消息报文约束
        MessageConstraints messageConstraints = MessageConstraints.custom()
            .setMaxHeaderCount(200)
            .setMaxLineLength(20000)
            .build();

        // 创建连接配置
        ConnectionConfig connectionConfig = ConnectionConfig.custom()
            .setMalformedInputAction(CodingErrorAction.IGNORE)
            .setUnmappableInputAction(CodingErrorAction.IGNORE)
            .setCharset(Consts.UTF_8)
            .setMessageConstraints(messageConstraints)
            .build();
        connManager.setDefaultConnectionConfig(connectionConfig);

        //配置最大的连接数
        connManager.setMaxTotal(100);
        //配合路由的最大连接数
        connManager.setDefaultMaxPerRoute(10);
        //创建http客户端
        client = HttpClients.custom().setConnectionManager(connManager).build();
    }

    /**
     * 描述: http or https post请求(body体参数)
     *
     * @param url          请求链接
     * @param parameterStr body体参数json的string格式
     * @return
     * @throws ConnectTimeoutException
     * @throws SocketTimeoutException
     * @throws Exception
     */
    public static HttpClientResult sendPost(String url, String parameterStr) throws ConnectTimeoutException, SocketTimeoutException, Exception {
        return post(url, parameterStr, APPLICATION_JSON_VALUE, CHARSET, null, CONNECT_TIME_OUT, READ_TIME_OUT);
    }

    /**
     * 描述: http or https post请求(body体参数)
     *
     * @param url          请求链接
     * @param parameterStr body体参数json的string格式
     * @param mimeType     消息类型,如application/json
     * @return
     * @throws ConnectTimeoutException
     * @throws SocketTimeoutException
     * @throws Exception
     */
    public static HttpClientResult sendPost(String url, String parameterStr, String mimeType) throws ConnectTimeoutException, SocketTimeoutException, Exception {
        return post(url, parameterStr, mimeType, CHARSET, null, CONNECT_TIME_OUT, READ_TIME_OUT);
    }

    /**
     * 描述: http or https post请求(body体参数)
     *
     * @param url          请求链接
     * @param parameterStr body体参数json的string格式
     * @param mimeType     消息类型
     * @param charset      字符编码
     * @param headers      请求头部参数
     * @param connTimeout  连接超时时间
     * @param readTimeout  响应超时时间
     * @return
     * @throws ConnectTimeoutException
     * @throws SocketTimeoutException
     * @throws Exception
     */
    public static HttpClientResult sendPost(String url, String parameterStr, String mimeType, String charset, Map<String, String> headers, Integer connTimeout, Integer readTimeout) throws ConnectTimeoutException,
    SocketTimeoutException, Exception {
        return post(url, parameterStr, mimeType, charset, headers, connTimeout, readTimeout);
    }

    /**
     * 描述: http or https post请求(form表单)
     *
     * @param url    请求链接
     * @param params form表单参数
     * @return
     * @throws ConnectTimeoutException
     * @throws SocketTimeoutException
     * @throws Exception
     */
    public static HttpClientResult sendFormPost(String url, Map<String, String> params) throws ConnectTimeoutException,
    SocketTimeoutException, Exception {
        return postForm(url, params, null, CONNECT_TIME_OUT, READ_TIME_OUT);
    }

    /**
     * 描述: http or https post请求(form表单)
     *
     * @param url     请求链接
     * @param params  form表单参数
     * @param headers 请求头部参数
     * @return
     * @throws ConnectTimeoutException
     * @throws SocketTimeoutException
     * @throws Exception
     */
    public static HttpClientResult sendFormPost(String url, Map<String, String> params, Map<String, String> headers) throws ConnectTimeoutException,
    SocketTimeoutException, Exception {
        return postForm(url, params, headers, CONNECT_TIME_OUT, READ_TIME_OUT);
    }

    /**
     * 描述: http or https post请求(form表单)
     *
     * @param url         请求链接
     * @param params      form表单参数
     * @param headers     请求头部参数
     * @param connTimeout 连接超时时间
     * @param readTimeout 响应超时时间
     * @return
     * @throws ConnectTimeoutException
     * @throws SocketTimeoutException
     * @throws Exception
     */
    public static HttpClientResult sendFormPost(String url, Map<String, String> params, Map<String, String> headers, Integer connTimeout, Integer readTimeout) throws ConnectTimeoutException,
    SocketTimeoutException, Exception {
        return postForm(url, params, headers, connTimeout, readTimeout);
    }

    /**
     * 描述: http or https get请求(不指定字符编码)
     * @param url 请求链接
     * @return
     * @throws Exception
     */
    public static HttpClientResult sendGet(String url) throws Exception {
        return get(url, CHARSET, null, null, null);
    }

    /**
     * 描述: http or https get请求(指定字符编码)
     * @param url 请求链接
     * @param charset 字符编码
     * @return
     * @throws Exception
     */
    public static HttpClientResult sendGet(String url, String charset) throws Exception {
        return get(url, charset, null, CONNECT_TIME_OUT, READ_TIME_OUT);
    }

    /**
     * 描述: http or https get请求 (指定请求头)
     * @param url 请求链接
     * @param charset 字符编码
     * @param headers 请求头键值对
     * @return
     * @throws Exception
     */
    public static HttpClientResult sendGet(String url, String charset, Map<String, String> headers) throws Exception {
        return get(url, charset, headers, CONNECT_TIME_OUT, READ_TIME_OUT);
    }

    /**
     * 描述: http or https get请求(指定字符编码和超时等待时间)
     * @param url 请求链接
     * @param charset 字符编码
     * @param headers 请求头键值对
     * @param connTimeout 连接超时时间
     * @param readTimeout 响应超时时间
     * @return
     * @throws Exception
     */
    public static HttpClientResult sendGet(String url, String charset, Map<String, String> headers, Integer connTimeout, Integer readTimeout) throws Exception {
        return get(url, charset, headers, connTimeout, readTimeout);
    }

    /**
     * 描述: http or https post请求处理方法(requestBody传参)
     *
     * @param url--请求链接
     * @param body--RequestBody
     * @param mimeType--消息类型:例如     application/xml "application/x-www-form-urlencoded"
     * @param charset--字符编码
     * @param headers--请求头键值对
     * @param connTimeout--连接超时时间
     * @param readTimeout--读取响应超时时间
     * @return
     * @throws ConnectTimeoutException
     * @throws SocketTimeoutException
     * @throws Exception
     */
    public static HttpClientResult post(String url, String body, String mimeType, String charset, Map<String, String> headers, Integer connTimeout, Integer readTimeout) throws IOException {
        HttpPost post = new HttpPost(url);
        HttpClientResult result = null;
        try {
            if (body != null && body.trim() != "") {
                HttpEntity entity = new StringEntity(body, ContentType.create(mimeType, charset));
                post.setEntity(entity);
            }
            if (headers != null && !headers.isEmpty()) {
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    post.addHeader(entry.getKey(), entry.getValue());
                }
            }
            //设置配置参数
            RequestConfig.Builder customReqConf = RequestConfig.custom();
            if (connTimeout != null) {
                customReqConf.setConnectTimeout(connTimeout);
            }
            if (readTimeout != null) {
                customReqConf.setSocketTimeout(readTimeout);
            }
            post.setConfig(customReqConf.build());
            result = responseToResult(client.execute(post));
        } finally {
            post.releaseConnection();
        }
        return result;
    }

    /**
     * 描述: http or https post请求处理方法(form表单传参)
     *
     * @param url--请求链接
     * @param params--参数键值对
     * @param headers--请求头键值对
     * @param connTimeout--连接超时时间
     * @param readTimeout--响应超时时间
     * @return
     * @throws ConnectTimeoutException
     * @throws SocketTimeoutException
     * @throws Exception
     */
    public static HttpClientResult postForm(String url, Map<String, String> params, Map<String, String> headers, Integer connTimeout, Integer readTimeout) throws IOException {
        HttpClientResult result = null;
        HttpPost post = new HttpPost(url);
        try {
            if (params != null && !params.isEmpty()) {
                List<NameValuePair> formParams = new ArrayList();
                Set<Map.Entry<String, String>> entrySet = params.entrySet();
                for (Map.Entry<String, String> entry : entrySet) {
                    formParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
                }
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formParams, Consts.UTF_8);
                post.setEntity(entity);
            }
            if (headers != null && !headers.isEmpty()) {
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    post.addHeader(entry.getKey(), entry.getValue());
                }
            }
            // 设置参数
            RequestConfig.Builder customReqConf = RequestConfig.custom();
            if (connTimeout != null) {
                customReqConf.setConnectTimeout(connTimeout);
            }
            if (readTimeout != null) {
                customReqConf.setSocketTimeout(readTimeout);
            }
            post.setConfig(customReqConf.build());
            result = responseToResult(client.execute(post));
        } finally {
            post.releaseConnection();
        }
        return result;
    }

    /**
     * 描述: http or https get请求处理方法
     *
     * @param url--请求链接
     * @param charset--字符编码
     * @param headers--请求头键值对
     * @param connTimeout--连接超时时间
     * @param readTimeout--响应超时时间
     * @return
     * @throws ConnectTimeoutException
     * @throws SocketTimeoutException
     * @throws Exception
     */
    public static HttpClientResult get(String url, String charset, Map<String, String> headers, Integer connTimeout, Integer readTimeout) throws IOException {
        HttpGet get = new HttpGet(url);
        HttpClientResult result = null;
        if (headers != null && !headers.isEmpty()) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                get.addHeader(entry.getKey(), entry.getValue());
            }
        }
        try {
            // 设置参数
            RequestConfig.Builder customReqConf = RequestConfig.custom();
            if (connTimeout != null) {
                customReqConf.setConnectTimeout(connTimeout);
            }
            if (readTimeout != null) {
                customReqConf.setSocketTimeout(readTimeout);
            }
            get.setConfig(customReqConf.build());
            result = responseToResult(client.execute(get));
        } finally {
            get.releaseConnection();
        }
        return result;
    }

    /**
     * 描述: http or https 文件中转上传
     *
     * @param serverUrl        上传地址
     * @param originalFileName 待上传文件名
     * @param bits             待上传文件二进制数组
     * @param uploadFieldName  上传后的文件名
     * @param params           其他的请求参数
     * @return
     * @throws IOException
     */
    public static HttpClientResult httpClientUpload(String serverUrl, String originalFileName, byte[] bits, String uploadFieldName, Map<String, String> params) throws IOException {
        HttpClientResult result = null;
        // 请求处理url
        HttpPost post = new HttpPost(serverUrl);
        try {
            // 创建待处理的文件
            ContentBody files = new ByteArrayBody(bits, originalFileName);
            // 对请求的表单域进行填充
            MultipartEntity reqEntity = new MultipartEntity();
            reqEntity.addPart(uploadFieldName, files);
            if (params != null && !params.isEmpty()) {
                for (Map.Entry<String, String> item : params.entrySet()) {
                    reqEntity.addPart(
                        item.getKey(),
                        new StringBody(URLEncoder.encode(
                            String.valueOf(item.getValue()), CHARSET)));
                }
            }
            // 设置请求
            post.setEntity(reqEntity);
            result = responseToResult(client.execute(post));
        } finally {
            post.releaseConnection();
        }
        return result;
    }

    /**
     * 描述: get请求url参数拼接
     * @param url 请求链接
     * @param params 请求参数
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String concatGetUrl(String url, Map<String, Object> params) throws UnsupportedEncodingException {
        StringBuffer buf = new StringBuffer(url);
        if (params != null) {
            if (!url.contains("?")) {
                buf.append("?");
            }
            for (Map.Entry<String, Object> item : params.entrySet()) {
                buf.append("&" + item.getKey() + "=" + URLEncoder.encode(String.valueOf(item.getValue()), "UTF-8"));
            }
        }
        return buf.toString();
    }

    /**
     * 处理http响应
     *
     * @param res
     * @return
     */
    private static HttpClientResult responseToResult(HttpResponse res) throws IOException {
        HttpClientResult result = new HttpClientResult();
        result.setCode(res.getStatusLine().getStatusCode());
        if (HttpStatus.SC_OK == res.getStatusLine().getStatusCode()) {
            HttpEntity entity = res.getEntity();
            result.setContent(EntityUtils.toString(entity, Consts.UTF_8));
        }
        return result;
    }
}

响应结果:

import java.io.Serializable;

/**
 * 响应结果
 * @author linhongwei
 */
public class HttpClientResult implements Serializable {
    
    private static final long serialVersionUID = -5152302877825031721L;

    /**
     * 响应状态码
     */
    private int code;

    /**
     * 响应数据
     */
    private String content;

    public int getCode() {
        return code;
    }

    public String getContent() {
        return content;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public void setContent(String content) {
        this.content = content;
    }
    
    public HttpClientResult() {
        super();
    }

    public HttpClientResult(int code) {
        super();
        this.code = code;
    }
    
    public HttpClientResult(String content) {
        super();
        this.content = content;
    }
    
    public HttpClientResult(int code, String content) {
        super();
        this.code = code;
        this.content = content;
    }
    
}

常见的HttpClient配置

PoolingHttpClientConnectionManager

PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
connManager.setMaxTotal(maxTotal);
connManager.setDefaultMaxPerRoute(maxPerRoute);

超时时间配置

final  RequestConfig config = RequestConfig.custom()
    .setConnectTimeout(connectTimeout)
    .setSocketTimeout(socketTimeout)
    .setConnectionRequestTimeout(connectionRequestTimeout)
    .build();

KeepAliveStrategy

ConnectionKeepAliveStrategy keepAliveStrategy = new DefaultConnectionKeepAliveStrategy() {
    @Override
    public long getKeepAliveDuration(final HttpResponse response, final HttpContext context) {
        long keepAlive = super.getKeepAliveDuration(response, context);
        if (keepAlive == -1) {
            keepAlive = defaultAliveTimeMills;
        }
        return keepAlive;
    }
};

Retry

public DefaultHttpRequestRetryHandler(final int retryCount, final boolean requestSentRetryEnabled) {
    this(retryCount, requestSentRetryEnabled, Arrays.asList(
        InterruptedIOException.class,
        UnknownHostException.class,
        ConnectException.class,
        SSLException.class));
}

Build

HttpClient httpClient = HttpClients.custom()
    .setConnectionManager(connManager)
    .setKeepAliveStrategy(keepAliveStrategy)
    .setDefaultRequestConfig(config)
    .setRetryHandler(new DefaultHttpRequestRetryHandler(3,true))
    .build();

 

posted @   残城碎梦  阅读(319)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
点击右上角即可分享
微信分享提示