1.基本使用
public class TestHttpClient {
public static void main(String[] args) throws IOException {
String url = "http://www.youku.com";
CloseableHttpClient client = HttpClients.custom().build();
HttpGet get = new HttpGet(url);
String s = client.execute(get, new myResponse());
System.out.println(s);
client.close();
}
/*用于处理响应的泛型类*/
static class myResponse implements ResponseHandler<String> {
@Override
public String handleResponse(HttpResponse httpResponse) throws IOException {
HttpEntity entity = httpResponse.getEntity();
if (entity != null) {
String s = EntityUtils.toString(entity);
return s;
}
return null;
}
}
}
httpclient的第二个参数接受一个responseHandler的泛型类,泛型是返回值类型,使用这种方法不需要手动关闭response,下面代码会自动帮忙关闭。下面是执行方法的源码,自动关闭在倒数第二行。
public <T> T execute(HttpHost target, HttpRequest request, ResponseHandler<? extends T> responseHandler, HttpContext context) throws IOException, ClientProtocolException {
Args.notNull(responseHandler, "Response handler");
CloseableHttpResponse response = this.execute(target, request, context);
Object result;
try {
result = responseHandler.handleResponse(response);
} catch (Exception var11) {
HttpEntity entity = response.getEntity();
try {
EntityUtils.consume(entity);
} catch (Exception var10) {
this.log.warn("Error consuming content after an exception.", var10);
}
if (var11 instanceof RuntimeException) {
throw (RuntimeException)var11;
}
if (var11 instanceof IOException) {
throw (IOException)var11;
}
throw new UndeclaredThrowableException(var11);
}
HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
return result;
}
2.访问https的网址。
https网址是通过tls加密的,所以我们要自定义证书验证器,这里我们允许所有的证书通过,创建新的空证书验证器并将它设置到httpclent上即可。
public static void main(String[] args) throws IOException, KeyManagementException, NoSuchAlgorithmException {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new X509TrustManager[]{new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}}, null);
String url = "https://www.baidu.com";
CloseableHttpClient client = HttpClients.custom().setSSLContext(sslContext).build();
HttpGet get = new HttpGet(url);
String s = client.execute(get, new myResponse());
System.out.println(s);
client.close();
}
/*用于处理响应的泛型类*/
static class myResponse implements ResponseHandler<String> {
@Override
public String handleResponse(HttpResponse httpResponse) throws IOException {
HttpEntity entity = httpResponse.getEntity();
if (entity != null) {
String s = EntityUtils.toString(entity);
return s;
}
return null;
}
}
初始化一个的SSLContext,并初始化它,我们这里选择的是
SSLContext.getInstance("TLS"); TLS版本,TLS版本还可以选择 “TLSv1.1” “TLSv1.2” 如果遇到返回协议版本错误的提示,说明和目标网站的协议版本不一致,可能是版本低了,我曾经遇到过这样的问题,把TLS换成TLSv1.2就能正常访问了。
3.多线程使用。
httpclient是线程安全的,我们没必要调用一次就创建一个httpclient对象,整个系统中只需要存在一个httpclient就行了。一般封装成工具类使用,我们用静态static关键字修饰httpclent即可。
网上有人说创建httpclient时传入poolinghttpClientConnectionmanager,我觉着是没必要的。
PoolingHttpClientConnectionManager pm = new PoolingHttpClientConnectionManager();
pm.setMaxTotal(200);
CloseableHttpClient client = HttpClients.custom().setSSLContext(sslContext).setConnectionManager(pm).build();
类似于上面这种用法,这种用法有两个问题,
1.在稍微老版本的httpclient中(4.3.*吧),如果我们设置了 SSLContext并且SSLContext.getInstance("TLSv1.2");这样创建的,那创建的链接池是不能自动变成TLSv1.2的,它获得的链接还是TLS,有些必须要求TLSv1.2的网站不能正常访问,
除非创建PoolingHttpClientConnectionManager时指定SSLContext为TLSv1.2,类似于这种创建方法
Registry<ConnectionSocketFactory> build = RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", new SSLConnectionSocketFactory(sslContext)).build();
PoolingHttpClientConnectionManager pm = new PoolingHttpClientConnectionManager(build);
pm.setMaxTotal(200);
CloseableHttpClient client = HttpClients.custom().setSSLContext(sslContext).setConnectionManager(pm).build();
上面这样长长的调用方法并不舒服。
2.不传入PoolingHttpClientConnectionManager会怎样?
我们在client的build方法中可以看到
如果我们没传入连接池,他会自动的创建一个链接池,并且创建的连接池是使用我们传入的sslcontext创建的,所以我们的协议版本他是支持的。