一、项目介绍Apache 提供用来做http请求的项目有两个,3.x 版本的项目叫做 The Commons HttpClient。它一开始是 Apache Jakarta Common 下的子项目,后来独立出去了,现在这个项目已经结束了它的生命周期,不再开发和维护。取而代之的是 4.x 版本的 Apache Httpcomponents 项目,它包括 HttpClient 和 HttpCore 两大模块,能提供更好的性能和更大的灵活性。二、项目模块Apache Httpcomponents 项目包括 HttpClient 和 HttpCore 两大模块,其中,HttpCore 是一套HTTP协议实现包。而 HttpClient 是基于HttpCore的一套客户端。三、使用方式使用 Httpclient 需要经过如下步骤创建 HttpClient创建 http 请求,如 HttpGet、HttpPost添加请求参数添加请求设置,如超时等使用 HttpClient 执行 http 请求读取返回内容并释放连接3.1 创建HttpClient3.1.1 创建默认客户端:复制代码1JAVA CloseableHttpClient httpclient = HttpClients.createDefault();
一些重要的默认配置:默认连接池大小10,每域名最大连接5连接池中连接存活时间 connTimeToLive = -1 ,默认单位为毫秒,默认连接不失效域名验证器为 DefaultHostnameVerifier , 会验证域名SSL 上下文为 SSLContext.getInstance("TLS"),没有使用密钥管理器(KeyManager)和信任管理器(TrustManager)3.1.2 自定义客户端失败不重试复制代码1JAVA CloseableHttpClient client = HttpClients.custom().setRetryHandler((e, i, c) -> false).build();
自定义连接池复制代码12345678910111213141516171819202122232425262728JAVA //设置自定义连接池
@Test
public void customConnectionPool() throws Exception {
//1.创建 https 需要的 SslContext 相关内容
//1.1 创建 SslContext
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(new FileInputStream("证书文件"), "密码".toCharArray());
SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(TrustAllStrategy.INSTANCE)
.loadKeyMaterial(ks, "证书密码".toCharArray()).build();
//1.2 创建 SSLConnectionSocketFactory
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, new String[]{"SSLv3", "TLSv1.1", "TLSv1.2"}, null,
NoopHostnameVerifier.INSTANCE);
//2.创建连接池
//2.1 构建协议 registry
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslConnectionSocketFactory)
.build();
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(registry);
//3.连接池针对所有连接、每域名的连接的数量设置
poolingHttpClientConnectionManager.setMaxTotal(100);
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(20);
//4.创建client
CloseableHttpClient client =
HttpClients.custom().setConnectionManager(poolingHttpClientConnectionManager).build();
}
3.2 创建 Http 请求创建 HttpGet、HttpPost 请求复制代码12345678910JAVA @Test
public void getAndPost(){
//1.创建get请求
HttpGet get = new HttpGet("https://www.baidu.com");
//2.创建post请求
HttpPost post = new HttpPost("https://www.baidu.com");
//3.其他如 HttpPut、HttpOptions、HttpTrace、HttpDelete、HttpPatch
}
3.3 添加请求参数复制代码12345678910111213141516171819202122232425262728293031323334353637383940JAVA @Test
public void addParams() throws IOException {
HttpPost post = new HttpPost("https://www.baidu.com");
//1.底层流,基础参数
BasicHttpEntity basicHttpEntity = new BasicHttpEntity();
//1.1添加参数内容
InputStream bis = new ByteArrayInputStream("参数".getBytes());
basicHttpEntity.setContent(bis);
//1.2设置内容长度
basicHttpEntity.setContentLength(bis.available());
//1.3取消分块发送
basicHttpEntity.setChunked(false);
post.setEntity(basicHttpEntity);
//2.字节码类型参数
HttpEntity entity = new ByteArrayEntity("name=zhangsan&age=100".getBytes());
post.setEntity(entity);
//3.字符串类型参数
entity = new StringEntity("name=zhangsan&age=100");
post.setEntity(entity);
//4.流式参数,用法与BasicHttpEntity类似,内容和长度严格匹配
entity = new InputStreamEntity(bis,bis.available());
post.setEntity(entity);
//5.文件类型参数
entity = new FileEntity(new File("上传文件"));
post.setEntity(entity);
//6.添加请求头
post.addHeader("Content-Type","text/html;charset=UTF-8");
Header contentType = new BasicHeader("Content-Type","text/html;charset=UTF-8");
post.addHeader(contentType);
Header host = new BasicHeader("Host","www.baidu.com");
post.setHeaders(new Header[]{contentType,host});
}
3.4 添加请求设置复制代码123456789101112131415JAVA @Test
public void requestConfig(){
//1.配置RequestConfig
RequestConfig requestConfig = RequestConfig.custom()
.setConnectionRequestTimeout(10000) //从连接池获取可用连接的超时时间,单位毫秒
.setSocketTimeout(5000) //请求获取数据的超时时间
.setConnectTimeout(4000) //连接超时时间
.build();
HttpPost post = new HttpPost("https://www.baidu.com");
//2.设置到post请求当中
post.setConfig(requestConfig);
//也可以当作默认值,设置到client当中,此client都会按这个超时处理
CloseableHttpClient client = HttpClients.custom().setDefaultRequestConfig(requestConfig).build();
}
3.4.1 超时时间说明超时类型说明connectionTimeout连接建立时间,即3次握手时间,默认值-1socketTimeout连接后,数据传输过程中数据包之间间隔的最大时间,默认值-1connectionRequestTimeout从连接池获取连接的超时时间,默认值-1注意:socketTimeout 和 connectionRequestTimeout 如果不设置,请求会阻塞。但是 connectionTimeout 的情况有所不同,它依赖于各平台的 socket 超时时间设置。windows 10 实测为 20s, linux 平台则不定,它会按 /proc/sys/net/ipv4/tcp_syn_retries 中配置的次数重试,一般为3s\7s\15s\31s\63s递增另外,即使 java 程序返回了超时结果,但是linux服务器依旧在执行重试直到服务器端超时,为了提高资源利用率,可以手动关闭关于 linux socket 超时的问题,请参阅 无悔的湖光-Al 的 从linux源码看socket(tcp)的timeout3.5 执行 http 请求执行 http 请求比较简单,直接调用 execute() 方法即可复制代码12345678910JAVA @Test
public void execute(){
CloseableHttpClient client = HttpClients.createDefault();
try {
client.execute(new HttpPost("https://www.baidu.com"));
client.execute(new HttpGet("https://www.baidu.com"));
} catch (IOException e) {
e.printStackTrace();
}
}
3.6 读取返回内容并释放连接服务器返回结果被封装到 HttpResponse 对象里,我们可以从这里拿到我们想要的返回结果复制代码123456789101112131415161718192021222324252627282930313233343536373839404142434445JAVA @Test
public void getResponse() {
CloseableHttpClient client = HttpClients.createDefault();
CloseableHttpResponse httpResponse = null;
final HttpGet httpGet = new HttpGet("https://www.baidu.com");
try {
httpResponse = client.execute(httpGet);
//1.获取返回状态
System.out.println(httpResponse.getStatusLine().getStatusCode());
//2.获取返回头信息
Header[] headers = httpResponse.getAllHeaders();
for (Header header : headers) {
System.out.println(header.getName() + ":" + header.getValue());
}
//3.获取返回消息体
HttpEntity entity = httpResponse.getEntity();
if(null != entity){
//3.1 得到返回结果并关闭流,与下面的只能执行一个,因为流只能读取一次
String content = EntityUtils.toString(entity);
System.out.println(content);
//3.2 得到返回结果并关闭流,与上面的只能执行一个
// byte[] contents = EntityUtils.toByteArray(entity);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != httpResponse) {
//4.归还连接到连接池
try {
httpResponse.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//如果复用 httpGet ,则重置其状态使其可以重复使用
httpGet.releaseConnection();
}
//只在应用关闭的时候关闭client
try {
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}原文链接:java处理http请求之Apache httpClient入门教程 – 去哪里吃鱼 – 博客园 (cnblogs.com)