在Java Web中,我们一般使用HttpComponent发起网络请求。HttpComponent获取分为两步:
1、获取到HttpClient
2、发起请求
今天来看一下如何配置HttpClient来达到我们想要的效果
一、连接池与设置HttpClient连接池数
HTTPComponent中有连接池的概念,比如我们有一个连接 连接了www.baidu.com ,那么当这个连接使用完毕后,下一个线程想要请求 www.baidu.com ,就可以直接使用这个连接,这是连接池的概念,那么我们如何去设置连接池的大小呢?
HTTPComponent中有两个连接管理器,一个是 BasicHttpClientConnectionManager ,一个是PoolingHttpClientConnectionManager。 BasicHttpClientConnectionManager 同一时间只能有一个连接,所以我们基本上不用,而PoolingHttpClientConnectionManager则为几乎所有人使用的连接管理器,也就是我们所说的连接池。
设置poolSize:
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();
// MaxPerRoute 设置一路有多大的缓存,比如访问 www.baidu.com 的为一路,那么访问 www.baidu.com 的连接最大限制到多少,比如是100,那么最多限制100个连接 www.baidu.com 的
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(100);
// 最多对外多少个连接,比如为 200 ,则为最大对外200个连接
poolingHttpClientConnectionManager.setMaxTotal(200);
注意连接不像连接数据库那样永远只有一种连接,HttpComponent中不同的域名是不同路的连接,连接成功后不能共用,所以 setDefaultMaxPerRoute 是设置相同路的最大连接数,setMaxTotal是设置最大的所有连接数。
二、如何设置默认的 connectionRequestTimeOut、connectionTimeOut、readTimeOut?
RequestConfig requestConfig = RequestConfig.custom().
setConnectionRequestTimeout(1000).
setConnectTimeout(1000).
setSocketTimeout(5000)
.build();
上述为设置超时时间,其中
1、connectionRequestTimeOut 为获取到 连接请求 的超时时间(也就是说获取到了连接请求 之后才能进行连接,否则需要等待 )。
2、ConnectTimeout 为连接的超时时间。
3、SocketTimeout为连接成功后 客户端和服务进行数据交互的超时时间,是指两者之间如果两个数据包之间的时间大于该时间则认为超时,而不是整个交互的整体时间,比如如果设置1秒超时,如果每隔0.8秒传输一次数据,传输10次,总共8秒,这样是不超时的。而如果任意两个数据包之间的时间超过了1秒,则超时。要注意SocketTimeout不是总时长,不过一般来说,我们经常会阻塞在服务端的处理过程中,服务端的返回一般在一个数据包内,就算是多个数据包,多个数据包发送也很快,所以SocketTimeOut一般可以看成是总时长。
上述为设置默认的超时时间,下节会讲到设置单次请求的超时时间。
三、设置ConnectionSocketFactory
PoolingHttpClientConnectionManager 为 连接请求 管理器,当获取到 连接请求 后,若此 连接请求 未与服务端连接,我们还需要进行连接,此时就用到了 ConnectionSocketFactory 。需要注意的是,HttpComponent中,HTTP的连接类默认只有一个 ,为 PlainConnectionSocketFactory ,HTTPS的连接类默认也只有一个,为 SSLConnectionSocketFactory 。
之所以要知道上述概念,是因为当我们发起https请求时,若对方服务端为自签的证书,则会报x509错误,一般情况下,我们会忽略这个错误,下面获取HttpClient的代码中讲到了如何忽略这个错误:
SSLContext sc = null;
try {
sc = SSLContext.getInstance("SSLv3");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
// 实现一个X509TrustManager接口,用于绕过验证,不用修改里面的方法
X509TrustManager trustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
String paramString) {
}
@Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
String paramString) {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
};
try {
sc.init(null, new TrustManager[]{trustManager}, null);
} catch (KeyManagementException e) {
e.printStackTrace();
}
// 设置协议http和https对应的处理socket链接工厂的对象
Registry socketFactoryRegistry = RegistryBuilder.create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", new SSLConnectionSocketFactory(sc))
.build();
四、获取到HttpClient:
此为获取到HttpClient的正确姿势:
public static CloseableHttpClient getHttpClient() {
SSLContext sc = null;
try {
sc = SSLContext.getInstance("SSLv3");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
// 实现一个X509TrustManager接口,用于绕过验证,不用修改里面的方法
X509TrustManager trustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
String paramString) {
}
@Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
String paramString) {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
};
try {
sc.init(null, new TrustManager[]{trustManager}, null);
} catch (KeyManagementException e) {
e.printStackTrace();
}
// 设置协议http和https对应的处理socket链接工厂的对象
Registry socketFactoryRegistry = RegistryBuilder.create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", new SSLConnectionSocketFactory(sc))
.build();
// 生成一个PoolingHttpClientConnectionManager
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
// MaxPerRoute 设置一路有多大的缓存,比如访问 www.baidu.com 的为一路,那么访问 www.baidu.com 的连接最大限制到多少,比如是100,那么限制最多有100个 www.baidu.com 的连接
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(100);
// 最多对外多少个连接,比如为 200 ,则为最大对外200个连接
poolingHttpClientConnectionManager.setMaxTotal(200);
// 设置超时时间
RequestConfig requestConfig = RequestConfig.custom().
setConnectionRequestTimeout(1000).
setConnectTimeout(1000).
setSocketTimeout(5000)
.build();
CloseableHttpClient httpClient = HttpClientBuilder.create()
// 设置默认的config,如果请求没有设置config的话,那么就用这个config
.setDefaultRequestConfig(requestConfig)
.setConnectionManager(poolingHttpClientConnectionManager)
.build();
return httpClient;
}