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();
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了