httpclient参数配置
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了httpclient参数配置相关的知识,希望对你有一定的参考价值。
参考技术A 这里简单解释一下httpclient一些关键参数的配置httpclient默认提供了一个策略
默认的话,是从response里头读timeout参数的,没有读到则设置为-1,这个代表无穷,这样设置是有点问题了,如果是https链接的话,则可能会经常报
HTTP规范没有确定一个持久连接可能或应该保持活动多长时间。一些HTTP服务器使用非标准的头部信息Keep-Alive来告诉客户端它们想在服务器端保持连接活动的周期秒数。如果这个信息可用,HttClient就会利用这个它。如果头部信息Keep-Alive在响应中不存在,HttpClient假设连接无限期的保持活动。然而许多现实中的HTTP服务器配置了在特定不活动周期之后丢掉持久连接来保存系统资源,往往这是不通知客户端的。
这里可以在此基础上重写一个,这里设置为5秒
官方提供了一个实例
在spring cloud netflix zuul中则提供了类似的定时器,只不过参数是写死的
spring-cloud-netflix-core/1.2.6.RELEASE/spring-cloud-netflix-core-1.2.6.RELEASE-sources.jar!/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilter.java
httpcore-4.4.6-sources.jar!/org/apache/http/pool/PoolEntry.java
主要看
httpclient-4.5.3-sources.jar!/org/apache/http/impl/execchain/ConnectionHolder.java
这里设置了validDuration,会传给releaseConnection
httpclient-4.5.3-sources.jar!/org/apache/http/impl/conn/PoolingHttpClientConnectionManager.java
这里去updateExpiry,相当于更新了timeToLive
这里设置的是http连接池中connection的存活时间
httpclient-4.5.3-sources.jar!/org/apache/http/impl/client/HttpClientBuilder.java
httpclient-4.5.3-sources.jar!/org/apache/http/impl/conn/PoolingHttpClientConnectionManager.java
4.0的ThreadSafeClientConnManager,在4.2版本的时候被废弃了,默认使用PoolingHttpClientConnectionManager。这个manager有两个重要的参数,一个是maxTotal,一个是defaultMaxPerRoute。
httpclient-4.5.3-sources.jar!/org/apache/http/conn/routing/HttpRoute.java
HttpRoute对象是immutable的,包含的数据有目标主机、本地地址、代理链、是否tunnulled、是否layered、是否是安全路由。
httpclient-4.5.3-sources.jar!/org/apache/http/impl/client/IdleConnectionEvictor.java
builder默认会构造一个IdleConnectionEvictor
httpclient-4.5.3-sources.jar!/org/apache/http/impl/client/HttpClientBuilder.java
如果没有指定maxIdleTime的话,但是有设置evictExpiredConnections的话,默认是10秒
设置从连接池获取一个连接的请求超时时间( 连接池中连接不够用的时候等待超时时间 ),单位毫秒,可以设置为500ms
httpclient-4.5.3-sources.jar!/org/apache/http/impl/execchain/MainClientExec.java
设置重试策略
httpclient-4.5.3-sources.jar!/org/apache/http/impl/client/DefaultHttpRequestRetryHandler.java
比如不重试,可以这样设置
当getKeepAliveDuration为-1以及connTimeToLive为-1的时候,closeExpiredConnections方法其实是没有用的,查看debug日志会出现
当getKeepAliveDuration不为-1的话,假设是5s,则日志可能是这样的
轻松把玩HttpClient之封装HttpClient工具类,插件式配置HttpClient对象
上一篇文章中,简单分享一下封装HttpClient工具类的思路及部分代码,本文将分享如何实现插件式配置HttpClient对象。
如果你看过我前面的几篇关于HttpClient的文章或者官网示例,应该都知道HttpClient对象在创建时,都可以设置各种参数,但是却没有简单的进行封装,比如对我来说比较重要的3个:代理、ssl(包含绕过证书验证和自定义证书验证)、超时。还需要自己写。所以这里我就简单封装了一下,顺便还封装了一个连接池的配置。
其实说是插件式配置,那是高大上的说法,说白了,就是采用了建造者模式来创建HttpClient对象(级联调用)。HttpClient的jar包中提供了一个创建HttpClient对象的类HttpClientBuilder。所以我是创建该类的子类HCB,然后做了一些改动。每个配置方法的返回值都是HCB,这样就支持级联调用了。具体代码如下:
package com.tgb.ccl.http.httpclient.builder;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import com.tgb.ccl.http.common.SSLs;
import com.tgb.ccl.http.exception.HttpProcessException;
/**
* httpclient创建者
*
* @author arron
* @date 2015年11月9日 下午5:45:47
* @version 1.0
*/
public class HCB extends HttpClientBuilder
private boolean isSetPool=false;//记录是否设置了连接池
private boolean isNewSSL=false;//记录是否设置了更新了ssl
//用于配置ssl
private SSLs ssls = SSLs.getInstance();
private HCB()
public static HCB custom()
return new HCB();
/**
* 设置超时时间
*
* @param timeout 超市时间,单位-毫秒
* @return
*/
public HCB timeout(int timeout)
// 配置请求的超时设置
RequestConfig config = RequestConfig.custom()
.setConnectionRequestTimeout(timeout)
.setConnectTimeout(timeout)
.setSocketTimeout(timeout)
.build();
return (HCB) this.setDefaultRequestConfig(config);
/**
* 设置ssl安全链接
*
* @return
* @throws HttpProcessException
*/
public HCB ssl() throws HttpProcessException
if(isSetPool)//如果已经设置过线程池,那肯定也就是https链接了
if(isNewSSL)
throw new HttpProcessException("请先设置ssl,后设置pool");
return this;
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
.<ConnectionSocketFactory> create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", ssls.getSSLCONNSF()).build();
//设置连接池大小
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
return (HCB) this.setConnectionManager(connManager);
/**
* 设置自定义sslcontext
*
* @param keyStorePath 密钥库路径
* @return
* @throws HttpProcessException
*/
public HCB ssl(String keyStorePath) throws HttpProcessException
return ssl(keyStorePath,"nopassword");
/**
* 设置自定义sslcontext
*
* @param keyStorePath 密钥库路径
* @param keyStorepass 密钥库密码
* @return
* @throws HttpProcessException
*/
public HCB ssl(String keyStorePath, String keyStorepass) throws HttpProcessException
this.ssls = SSLs.custom().customSSL(keyStorePath, keyStorepass);
this.isNewSSL=true;
return ssl();
/**
* 设置连接池(默认开启https)
*
* @param maxTotal 最大连接数
* @param defaultMaxPerRoute 每个路由默认连接数
* @return
* @throws HttpProcessException
*/
public HCB pool(int maxTotal, int defaultMaxPerRoute) throws HttpProcessException
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
.<ConnectionSocketFactory> create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", ssls.getSSLCONNSF()).build();
//设置连接池大小
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
connManager.setMaxTotal(maxTotal);
connManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
isSetPool=true;
return (HCB) this.setConnectionManager(connManager);
/**
* 设置代理
*
* @param hostOrIP 代理host或者ip
* @param port 代理端口
* @return
*/
public HCB proxy(String hostOrIP, int port)
// 依次是代理地址,代理端口号,协议类型
HttpHost proxy = new HttpHost(hostOrIP, port, "http");
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
return (HCB) this.setRoutePlanner(routePlanner);
大家可以看到,这个有成员变量,而且不是static类型,所以是非线程安全的。所以我为了方便使用,就效仿HttpClients(其custom方法可以创建HttpClientBuilder实例)写了一个静态的custom方法,来返回一个新的HCB实例。将构造方法设置成了private,无法通过new的方式创建实例,所以只能通过custom方法来创建。在想生成HttpClient对象的时候,调用一下build方法就可以了。于是乎就出现了这样简单、方便又明了的调用方式:
HttpClient client = HCB.custom().timeout(10000).proxy("127.0.0.1", 8087).ssl("D:\\\\keys\\\\wsriakey","tomcat").build();
说到ssl,还需要另外一个封装的类,为了其他工具类有可能也会用到ssl,所以就单出来了。不多解释,直接上代码:
/**
* 设置ssl
*
* @author arron
* @date 2015年11月3日 下午3:11:54
* @version 1.0
*/
public class SSLs
private static final SSLHandler simpleVerifier = new SSLHandler();
private static SSLConnectionSocketFactory sslConnFactory ;
private static SSLs sslutil = new SSLs();
private SSLContext sc;
public static SSLs getInstance()
return sslutil;
public static SSLs custom()
return new SSLs();
// 重写X509TrustManager类的三个方法,信任服务器证书
private static class SSLHandler implements X509TrustManager, HostnameVerifier
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers()
return null;
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain,
String authType) throws java.security.cert.CertificateException
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain,
String authType) throws java.security.cert.CertificateException
@Override
public boolean verify(String paramString, SSLSession paramSSLSession)
return true;
;
// 信任主机
public static HostnameVerifier getVerifier()
return simpleVerifier;
public synchronized SSLConnectionSocketFactory getSSLCONNSF() throws HttpProcessException
if (sslConnFactory != null)
return sslConnFactory;
try
SSLContext sc = getSSLContext();
sc.init(null, new TrustManager[] simpleVerifier , null);
sslConnFactory = new SSLConnectionSocketFactory(sc, simpleVerifier);
catch (KeyManagementException e)
throw new HttpProcessException(e);
return sslConnFactory;
public SSLs customSSL(String keyStorePath, String keyStorepass) throws HttpProcessException
FileInputStream instream =null;
KeyStore trustStore = null;
try
trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
instream = new FileInputStream(new File(keyStorePath));
trustStore.load(instream, keyStorepass.toCharArray());
// 相信自己的CA和所有自签名的证书
sc= SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()) .build();
catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException | KeyManagementException e)
throw new HttpProcessException(e);
finally
try
instream.close();
catch (IOException e)
return this;
public SSLContext getSSLContext() throws HttpProcessException
try
if(sc==null)
sc = SSLContext.getInstance("SSLv3");
return sc;
catch (NoSuchAlgorithmException e)
throw new HttpProcessException(e);
基本上就是这样了。在上一篇中遗留了一个小问题,正好在这里说一下。上一篇文中说道提供一个默认的HttpClient实现,其实是2个,分别针对于http和https。方便调用。具体代码如下:
//默认采用的http协议的HttpClient对象
private static HttpClient client4HTTP;
//默认采用的https协议的HttpClient对象
private static HttpClient client4HTTPS;
static
try
client4HTTP = HCB.custom().build();
client4HTTPS = HCB.custom().ssl().build();
catch (HttpProcessException e)
logger.error("创建https协议的HttpClient对象出错:", e);
/**
* 判断url是http还是https,直接返回相应的默认client对象
*
* @return 返回对应默认的client对象
* @throws HttpProcessException
*/
private static HttpClient create(String url) throws HttpProcessException
if(url.toLowerCase().startsWith("https://"))
return client4HTTPS;
else
return client4HTTP;
这样在使用工具类的时候,如果不需要自定义HttpClient时,就直接用下面的方式调用:
public static void testSimple() throws HttpProcessException
String url = "http://tool.oschina.net/";
//简单调用
String resp = HttpClientUtil.send(url);
System.out.println("请求结果内容长度:"+ resp);
好了,插件化配置HttpClient,就是这些内容,在下一篇文章中分享如何插件式配置Header。没错,思路还是跟本文一样。敬请期待吧。
代码已上传至:https://github.com/Arronlong/httpclientUtil。
httpclientUtil (QQ交流群:548452686 )
以上是关于httpclient参数配置的主要内容,如果未能解决你的问题,请参考以下文章
轻松把玩HttpClient之封装HttpClient工具类,插件式配置HttpClient对象
轻松把玩HttpClient之封装HttpClient工具类,封装输入参数,简化工具类
轻松把玩HttpClient之封装HttpClient工具类,封装输入参数,简化工具类