网站首页 > 精选教程 正文
在今天这个编程时代,无时无刻不需要与网络打交道。因此,一个良好的网络请求框架是编程中必不可少的一个类库了。
而在Java 8占据主流的时代中,做为Java 程序员,最喜欢或使用的最多的几个网络类库分别应该是:
- Apache Http Client
- Spring RestTemplate
当然,JDK本身也有一个HttpUrlConnection的类,是用来做网络请求的。
但你知道么,在JDK 11的时候,Java引进了一个新的Java Http Client网络请求的新特性。
这又是怎么一回事呢?
这一次,我来聊聊Java 8之后的新特性,网络请求Java Http Client。本篇是Java 8之后的那些新特性系列的第四篇,这个系列的其它几篇文章分别是:
- Java 8之后的那些新特性(一):局部变量var
- Java 8之后的那些新特性(二):文本块 Text Blocks
- Java 8之后的那些新特性(三):Java System Logger
HttpUrlConnection
首先,来说下HttpUrlConnection这个JDK自带的网络请求实现。
事实上,直接使用HttpUrlConnection的应该比较少,HttpUrlConnection非常基础,封装不够,这使得基于HttpUrlConnection来做一个简单的GET请求你都得从头开始写一大堆代码。
@Test
void testHttpURLConnection() throws Exception{
var url = new URL("https://taoofcoding.tech");
var con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
var in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer content = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
content.append(inputLine);
}
in.close();
Assertions.assertNotNull(content);
}
这还是简单的GET请求,你可以想像下其它POST,PUT等这些需要传递大量BODY内容是需要写多少这样类似的代码。
而且HttpUrlConnection还有很多其它问题,比如不支持HTTP/2,不支持异步响应式网络请求等。这使得它真正应用并不多。
第三方类库
由于HttpUrlConnection的缺点,于是更优雅的类库来补充就成为一种必然的事。而在这些第三方类库中,以Apache Http Client与Spring的RestTemplate两个最为流行。
Apache是因为其在Java生态中一贯的影响力与质量,它提供了非常多的对JDK的补充类库,而且质量极高。而RestTemplate则是搭乘Spring这股春风,由于Spring的不断流行,使得RestTemplate也跟着流行起来了。
我们来看下Apache Http Client与RestTemplate的代码是怎么样的。
Apache Http Client
@Test
//apache http client旧有模式
void testApacheHttpClient() throws Exception {
try(var httpclient = HttpClients.createDefault()){
var httpGet = new HttpGet("https://taoofcoding.tech");
try(var response = httpclient.execute(httpGet)){
var content = EntityUtils.toString(response.getEntity());
Assertions.assertNotNull(content);
}
}
}
@Test
//apache httpe client Fluent API模式
void testApacheFluentHttpClient() throws IOException {
var content = Request.get("https://taoofcoding.tech")
.execute().returnContent();
Assertions.assertNotNull(content);
}
RestTemplate
@Test
void testRestTemplate(){
var restTemplate = new RestTemplate();
var response = restTemplate.getForEntity("https://taoofcoding.tech",String.class);
var content = response.getBody();
Assertions.assertNotNull(content);
}
从上面这个简单的示例代码中,可以看到,http client也好,restTemplate也好,比起HttpUrlConnection都要简洁很多。
而且,从功能上,这些第三方类库在以下功能点上也远优于HttpUrlConnection
- 都提供了对HTTP/2的支持
- Apache Http Client支持异步网络请求(响应式网络请求),Spring 5则提供了WebClient来支持响应式网络请求
- 请求连接池管理等能力
而从简洁度与功能完善度上来说,Apache Http Client更佳,特别是5之后它提供了Fluent Api,使得代码更简洁与优雅了。
Java Http Client
好吧,我们回到这篇文章的主题上,Apache Http Client是个很优秀的类库,这是没有太多疑问的,但这就如同日志功能一样,它毕竟不属于JDK级别的。
JAVA语言一直在不断的改进,它也知道旧的HttpUrlConnection是比较难用,而且非常罗嗦的。于是在Java 11的时候,Java引进了新的Java Http Client,用来取代旧有的HttpUrlConnection。
Java Http Client的特点是:
- 它支持HTTP/2
- 它支持同步及异步网络请求两种模式
- 它使用的Fluent方式来设置各种网络请求参数
我们用最新的Java Http Client来重写上面的示例。
@Test
//java http client同步模式
void testJavaHttpClient() throws IOException, InterruptedException {
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder()
.uri(URI.create("https://taoofcoding.tech"))
.timeout(Duration.ofMinutes(1))
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
Assertions.assertNotNull(response.body());
}
@Test
//java http client异步模式
void testAsyncJavaHttpClient() throws ExecutionException, InterruptedException {
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder()
.uri(URI.create("https://taoofcoding.tech/"))
.timeout(Duration.ofMinutes(1))
.build();
var completableFuture = client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(response -> { System.out.println(response.statusCode());
return response; } )
.thenApply(HttpResponse::body)
.thenAccept(System.out::println);
completableFuture.get();
}
从代码上可以明显看到,它与Java Http Client在简洁与优雅已经差不多在同一个级别了。
但在功能丰富度上,仍然比不上Apache Http Client,比如没有请求连接池管理等。
优势与缺点
和在上一篇文章中说的Java System Logger一样,JDK级别的东西的一个最大的优势是你不需要再多依赖一个第三方库,并且JDK级别的功能你可以期望它是稳定的,一直被维护的。
一旦JDK有的东西,实现上又很简洁与优雅,就没有太多理由再去用第三方类库。
毕竟,依赖任何一个第三方类库都存在依赖传递的问题,你依赖的东西可能依赖另一些类库,这些不同的依赖会给代码增加依赖方面的复杂度。而使用JDK级别的就没有此担忧了。
还是说缺点吧。
从我的使用过程中看,这个Java Http Client缺少了处理网络请求中一个非常有用的点,就是对响应结果的封装处理。
我在这里用基于restTemplate的代码示例来说明。
@Test
void testRegisterUser(){
//我们直接将结果转换为UserVO对象了
ResponseEntity<UserVO> registerResponse = restTemplate.exchange(
baseUrl()+"/v1/users/register",
HttpMethod.PUT,
createHttpEntityFromString(randomRegisterUser()),
UserVO.class);
Assertions.assertTrue(registerResponse.getStatusCode().is2xxSuccessful());
}
每个网络请求,我们拿到结果后,期望的并不会是一个String或inputStream这样的结果,而是期望将这个String或InputStream转化为一个具体我们期望的类。
比如上述代码中,我们期望返回直接就是UserVO,而不是String或一个InputStream。
好在第三方类库在这方面都支持非常到位。
但Java Http Client则默认你只能期望将结果转换为以下类型.
HttpResponse.BodyHandlers::ofByteArray()
HttpResponse.BodyHandlers::ofString()
HttpResponse.BodyHandlers::ofFile(Path)
HttpResponse.BodyHandlers::discarding()
当然,你可以自己实现对应的接口,来转换为具体的类。但这也意味着我们得额外多做一步。
那我们思考下,为什么Java Http Client没有提供这么一个有用的功能?
原因就是:
JDK不能依赖第三方类库,而JDK本身提供任何功能都是非常谨慎的
把一个JSON字符转换为具体的类,这个能力JDK本身并没有提供,所以Java Http Client当然做不到这一点。
而对于第三方类库来说,它可以自行实现这个功能或再多依赖一个第三方框架来实现这个功能就好了。
所以,JDK级别的能力一定是最可靠的,这也是为什么我认为我们要非常关注JDK级别的新特性的原因所在。
关于Java Http Client的就聊到这了,未来你会愿意使用Java Http Client么?
对我而言,这是没有任何疑问的选择。
好了,下周我再继续和大家聊一聊Java 8之后的新特性。
猜你喜欢
- 2024-11-05 关于 URL,说几个你不知道的点 url各部分含义
- 2024-11-05 避免自己写的 url 被diss!建议看看这篇RESTful API简明教程!
- 2024-11-05 IntelliJ IDEA 15款 神级超级牛逼插件推荐
- 2024-11-05 学习SpringMVC——如何获取请求参数
- 2024-11-05 java验证码生成(一) java生成验证码并验证
- 2024-11-05 Nice,终于有人把SpringMVC讲明白了,太简单了...
- 2024-11-05 Java代理IP设置指南:让你的网络请求更灵活
- 2024-11-05 请说说RPC的一个请求的流程是怎么样的?
- 2024-11-05 Javaweb 演示session的URL重写 java sessionid
- 2024-11-05 springboot2.2.X手册:构建全局唯一的短链接数据中心
你 发表评论:
欢迎- 04-11Java面试“字符串三兄弟”String、StringBuilder、StringBuffer
- 04-11Java中你知道几种从字符串中找指定的字符的数量
- 04-11探秘Java面试中问的最多的String、StringBuffer、StringBuilder
- 04-11Python字符串详解与示例(python字符串的常见操作)
- 04-11java正则-取出指定字符串之间的内容
- 04-11String s1 = new String("abc");这句话创建了几个字符串对象?
- 04-11java判断字符串中是否包含某个字符
- 04-11关于java开发中正确的发牌逻辑编写规范
- 最近发表
-
- Java面试“字符串三兄弟”String、StringBuilder、StringBuffer
- Java中你知道几种从字符串中找指定的字符的数量
- 探秘Java面试中问的最多的String、StringBuffer、StringBuilder
- Python字符串详解与示例(python字符串的常见操作)
- java正则-取出指定字符串之间的内容
- String s1 = new String("abc");这句话创建了几个字符串对象?
- java判断字符串中是否包含某个字符
- 关于java开发中正确的发牌逻辑编写规范
- windows、linux如何后台运行jar(并且显示进程名)
- 腾讯大佬私人收藏,GitHub上最受欢迎的100个JAVA库,值得学习
- 标签列表
-
- nginx反向代理 (57)
- nginx日志 (56)
- nginx限制ip访问 (62)
- mac安装nginx (55)
- java和mysql (59)
- java中final (62)
- win10安装java (72)
- java启动参数 (64)
- java链表反转 (64)
- 字符串反转java (72)
- java逻辑运算符 (59)
- java 请求url (65)
- java信号量 (57)
- java定义枚举 (59)
- java字符串压缩 (56)
- java中的反射 (59)
- java 三维数组 (55)
- java插入排序 (68)
- java线程的状态 (62)
- java异步调用 (55)
- java中的异常处理 (62)
- java锁机制 (54)
- java静态内部类 (55)
- java怎么添加图片 (60)
- java 权限框架 (55)
本文暂时没有评论,来添加一个吧(●'◡'●)