HttpClient 是Apache Jakarta Common 下的子项目,可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。
我们可以通过这个HttpClient工具,在java代码中去构造和发送http请求
要搞清楚编程语言层面http client的使用,就得先对http协议有所了解。
你应该知道http的transfer layer(传输层)其实是tcp协议
,而tcp协议最关键的就是一次连接的建立到释放需要经过三次握手,四次挥手。
那么如果你连续访问同一个服务器n次,就得建立n次连接,显然很耗费时间,用户使用体验不好,也没有必要。
于是从HTTP1.1协议开始,有了所谓的长连接(persistent connection)
,而且客户端默认行为就是长连接(需要服务端也打开长连接才能实际生效),有了长连接,那么原来
一次连接=一次请求+一次响应,现在可以一次连接=(一次请求+一次响应)*n,n>=1。
tips:注意连接和请求是两个不同的概念。
这样子对于连续n次请求同一服务器的场景来说,就比原来减少了n-1次连接,也就是减少了(3次握手+4次挥手)*(n-1)的时间。
当然,在实际使用中,这里的请求次数n
是有limitation的,即使你没有手动设置,其本身肯定也有一个默认值。
除了请求数量上有限制外,一般还有时间上的限制,这里的时间限制包括连接的空闲时间
和最大存活时间
(这两个概念是不同的)。上面我使用了连续请求这个词语,连续是个很抽象的概念,得使用量级去定义它,所以timeout就表明了两次连接时间间隔得在timeout内才算作连续。超过这个时间长连接会被释放掉。
一般在请求头或者响应头通过这个字段定义:
Keep-Alive: timeout=5, max=1000
这表明长连接的空闲时间为5s,时间单位是秒。
tips:在软件设计中,边界思想是很重要的。
那客户端这一头是如何控制开启长短连接的呢?
请求头的这个字段:Connection。
Connection: close->禁止长连接
Connection: keep-alive->使用长连接
官网原话是:
HTTP/1.1 defines the “close” connection option for the sender to signal that the
connection will be closed after completion of the response.
由于默认行为是长连接了(相当于默认值keep-alive),所以如果不想要长连接,那么需要显示指明这个请求头
字段的值为close。
有时候要小心一点的就是服务端没有打开长连接的支持(默认打开),虽然一般情况下不会有人这么做,但是原理还是要知道的。
还有一点就是连接的关闭可以分为client主动关闭还是server端关闭,并不一定总是server端关闭的连接。
在apache http client中,连接是由连接管理对象来管理,有两种类型。
一种是Simple connection manager(对应的是asicHttpClientConnectionManager.java),
一种就是Pooling connection manager(对应的是PoolingHttpClientConnectionManager.java)。
从名字上看就知道一个是一个http client对应一个connection,一个是一个http client对应一个connection pool,既然是pool,那么connection的数量就可能是n。
tips:http client和connection是两个不同的概念。
需要注意的是,如果没有明确的指定connnection manager,通过HttpClientBuilder.java创建http client的话默认会为你创建的是Pooling connection manager。
根据实际需要选择,一般我都偏向于将http client作为单例使用。
了解http 来自:https://zhuanlan.zhihu.com/p/341584129
采用的是阿里云的sdk-oss(包含了httpclient)
<dependency>
<groupId>com.aliyun.ossgroupId>
<artifactId>aliyun-sdk-ossartifactId>
dependency>
/**
* 测试通过httpclient发送GET方式的请求
*/
@Test
public void testGET() throws Exception{
//创建httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
//创建请求对象
HttpGet httpGet = new HttpGet("http://localhost:8080/user/shop/status");
//发送请求,接受响应结果
CloseableHttpResponse response = httpClient.execute(httpGet);
//获取服务端返回的状态码
int statusCode = response.getStatusLine().getStatusCode();
System.out.println("服务端返回的状态码为:" + statusCode);
HttpEntity entity = response.getEntity();
String body = EntityUtils.toString(entity);
System.out.println("服务端返回的数据为:" + body);
//关闭资源
response.close();
httpClient.close();
}
/**
* 测试通过httpclient发送POST方式的请求
*/
@Test
public void testPOST() throws Exception{
// 创建httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
//创建请求对象
HttpPost httpPost = new HttpPost("http://localhost:8080/admin/employee/login");
JSONObject jsonObject = new JSONObject();
jsonObject.put("username","admin");
jsonObject.put("password","123456");
StringEntity entity = new StringEntity(jsonObject.toString());
//指定请求编码方式
entity.setContentEncoding("utf-8");
//数据格式
entity.setContentType("application/json");
httpPost.setEntity(entity);
//发送请求
CloseableHttpResponse response = httpClient.execute(httpPost);
//解析返回结果
int statusCode = response.getStatusLine().getStatusCode();
System.out.println("响应码为:" + statusCode);
HttpEntity entity1 = response.getEntity();
String body = EntityUtils.toString(entity1);
System.out.println("响应数据为:" + body);
//关闭资源
response.close();
httpClient.close();
}