安全矩阵

 找回密码
 立即注册
搜索
查看: 429|回复: 0

10 个例子精通 Java 11 HttpClient

[复制链接]

251

主题

270

帖子

1783

积分

金牌会员

Rank: 6Rank: 6

积分
1783
发表于 2023-1-11 19:10:54 | 显示全部楼层 |阅读模式
本帖最后由 Meng0f 于 2023-1-11 19:13 编辑

转载于:Java面试攻略 2023-01-10 19:35 发表于上海
一、前言
Java11 之前 java 只提供了 HttpURLConnection API,它并不太好用,而且性能差。因此,通常大家使用的第三方库,如 Apache HttpClient、Jetty、okhttp 和 Spring 的 RestTemplate。

与 HttpURLConnection 不同,java11 的 HTTP Client 提供了同步和异步请求机制。

API 包括3个中心类:HttpRequest 表示 HttpClient 需要发送的请求。HttpClient 用于发送同步或异步请求。HttpResponse 表示 HttpRequest 调用的最终结果。我们将在下面的章节中更详细地介绍它们。首先,让我们关注一个请求。
image.png

二、HttpClient 同步和异步
让我们先看看 Javadoc 中的同步示例,了解如何使用  HttpClient 发送同步请求:
  1. HttpClient client = HttpClient.newBuilder()
  2.         .version(Version.HTTP_1_1)
  3.         .followRedirects(Redirect.NORMAL)
  4.         .connectTimeout(Duration.ofSeconds(20))
  5.         .proxy(ProxySelector.of(new InetSocketAddress("proxy.example.com", 80)))
  6.         .authenticator(Authenticator.getDefault())
  7.         .build();

  8. HttpRequest request = HttpRequest.newBuilder()
  9.         .uri(URI.create("https://www.dreamlu.net"))
  10.         .timeout(Duration.ofMinutes(2))
  11.         .header("Content-Type", "application/json")
  12.         .POST(BodyPublishers.ofFile(Paths.get("file.json")))
  13.         .build();

  14. HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
  15. System.out.println(response.statusCode());
  16. System.out.println(response.body());
复制代码

在这种情况下,您的程序将发送请求并等待响应,一旦收到响应,它将打印状态代码和响应主体。

现在,让我们看一个使用 HttpClient API 在 Java 中异步调用 REST API 的示例:
  1. HttpClient client = HttpClient.newBuilder()
  2.     .build();

  3. HttpRequest request = HttpRequest.newBuilder()
  4.         .uri(URI.create("https://www.dreamlu.net"))
  5.         .timeout(Duration.ofMinutes(2))
  6.         .header("Content-Type", "application/json")
  7.         .POST(BodyPublishers.ofFile(Paths.get("file.json")))
  8.         .build();

  9. client.sendAsync(request, BodyHandlers.ofString())
  10.         .thenApply(HttpResponse::body)
  11.         .thenAccept(System.out::println);
复制代码

上面示例中使用了 sendAsync() 方法而不是 send() 方法。这意味着,使用 HttpClient.send() 发送同步请求,使用 HttpClient.sendAsync() 向任何HTTP服务器或 RESTful Web 服务发出异步请求。

现在,让我们来看看如何在 HttpRequest 添加超时、Headers 和 cookie 等参数。

三、HttpRequest 请求
1. HttpRequest
HttpRequest 是一个表示我们需要发送的请求。使用 HttpRequest.Builder 可以创建新的实例。我们可以通过调用 HttpRequest.newBuilder() 来实现。

在 JDK16 中,有一个全新的 HttpRequest.newBuilder(HttpRequest request, BiPredicate filter) 方法,它创建了一个生成器,它的配置是从已经存在的 HttpRequest 复制。
image.png

2. 如何设置 URI
Setting up a URI is actually the first thing you need to do when creating a new request. That is, you need to provide a URL. This can be done in a couple of ways. You can use a constructor for a Builder along with a URI parameter. You can then call uri(URI) on the instance Builder.

设置 URI 实际上是创建新 request 时需要做的第一件事。可以通过多种方式实现。您可以将 Builder 与URI参数一起用于构造器。然后可以在实例生成器上调用 URI(uri) 方法。
  1. HttpRequest.newBuilder(new URI("https://www.dreamlu.net/get"))

  2. HttpRequest.newBuilder()
  3.            .uri(new URI("https://www.dreamlu.net/get"))
复制代码


3. 如何制定 HTTP Method
你可以定义请求使用的 HTTP method。这可以通过调用 Builder 中的方法来完成。这些方法是:
  • GET()
  • POST(BODYPUBLISHER Body)
  • PUT(BODYPUBLISHER Body)
  • DELETE()

如下,创建一个简单的 GET 请求。
  1. HttpRequest request = HttpRequest.newBuilder()
  2.   .uri(new URI("https://www.dreamlu.net/get"))
  3.   .GET()
  4.   .build();
复制代码


4. 如何设置 HTTP 协议版本
HttpClient API 完全支持 HTTP 2 协议,并且默认情况下使用 HTTP 2。我们可以通过 Builder 的 version() 方法来设置:
  1. HttpRequest request = HttpRequest.newBuilder()
  2.   .uri(new URI("https://www.dreamlu.net/get"))
  3.   .version(HttpClient.Version.HTTP_2)
  4.   .GET()
  5.   .build();
复制代码

注意:如果不支持 HTTP2,HttpClient 会自动切换到 HTTP1.1。
5. 如何设置 Headers 请求头
向请求中添加 headers 也非常容易。这可以通过使用 Builder 的 headers() 方法轻松完成。
  1. HttpRequest request = HttpRequest.newBuilder()
  2.   .uri(new URI("https://www.dreamlu.net/get"))
  3.   .headers("key1", "value1", "key2", "value2")
  4.   .GET()
  5.   .build()

  6. HttpRequest request2 = HttpRequest.newBuilder()
  7.   .uri(new URI("https://www.dreamlu.net/get"))
  8.   .header("key1", "value1")
  9.   .header("key2", "value2")
  10.   .GET()
  11.   .build();
复制代码


6. 如何设置 Timeout
您可以使用 Timeout 设置等待某个响应所需的时间。如果超时,将抛出 HttpTimeoutException。默认情况下,它实际上设置为无穷大。它也可以通过使用 Timeout() 方法使用 Duration 对象设置。
  1. HttpRequest request = HttpRequest.newBuilder()
  2.   .uri(new URI("https://www.dreamlu.net/get"))
  3.   .timeout(Duration.of(10, SECONDS))
  4.   .GET()
  5.   .build()
复制代码


7. 如何设置请求 Body
可以通过使用 request builder 方法(如 POST(BodyPublisher body)、PUT(BodyPublisher body) 和 DELETE() 将主体添加到请求中。如果没有请求报文,可以简单地传递 HttpRequest.BodyPublishers.noBody()。
  1. HttpRequest request = HttpRequest.newBuilder()
  2.   .uri(new URI("https://www.dreamlu.net/post"))
  3.   .POST(HttpRequest.BodyPublishers.noBody())
  4.   .build();
复制代码


8. 如何发送 String Body
可以用 BodyPublishers 以非常简单直观的方式设置任何 request body。您可以简单地将 String 作为 Body 传递。或者也可以使用 StringBodyPublisher。也可以使用 String() 的简单工厂方法创建此对象。这实际上将以字符串对象作为参数,然后创建一个 request Body。
  1. HttpRequest request = HttpRequest.newBuilder()
  2.   .uri(new URI("https://www.dreamlu.net/post"))
  3.   .headers("Content-Type", "text/plain;charset=UTF-8")
  4.   .POST(HttpRequest.BodyPublishers.ofString("Sample request body"))
  5.   .build();
复制代码


9. 如何发送 InputStream Body
必须以 Supplier 传递 InputStream。这与 StringBodyPublishers 有点不同。
  1. byte[] sampleData = "Sample request body".getBytes();

  2. HttpRequest request = HttpRequest.newBuilder()
  3.   .uri(new URI("https://www.dreamlu.net/post"))
  4.   .headers("Content-Type", "text/plain;charset=UTF-8")
  5.   .POST(HttpRequest.BodyPublishers
  6.    .ofInputStream(() -> new ByteArrayInputStream(sampleData)))
  7.   .build();
复制代码

在这段代码中使用简单的 ByteArrayInputStream,也可以使用其他任何 InputStream 实现。

10. 如何发送 ByteArray
可以使用 ByteArrayProcessor 来传递字节数组作为参数。
  1. byte[] sampleData = "Sample request body".getBytes();

  2. HttpRequest request = HttpRequest.newBuilder()
  3.   .uri(new URI("https://www.dreamlu.net/post"))
  4.   .headers("Content-Type", "text/plain;charset=UTF-8")
  5.   .POST(HttpRequest.BodyPublishers.ofByteArray(sampleData))
  6.   .build();
复制代码


四、总结
单纯就使用体验来说 java11 HttpClient 使用并不如笔者开源的 mica-http(基于 okhttp)方便。示例(mica-http 请求代码):
  1. // 同步,异常时 返回 null
  2. String html = HttpRequest.get("https://www.baidu.com")
  3. .connectTimeout(Duration.ofSeconds(1000))
  4. .query("test", "a")
  5. .query("name", "張三")
  6. .query("x", 1)
  7. .query("abd", Base64Util.encode("123&$#%"))
  8. .queryEncoded("abc", Base64Util.encode("123&$#%"))
  9. .execute()
  10. .onFailed(((request, e) -> {
  11.   e.printStackTrace();
  12. }))
  13. .onSuccess(ResponseSpec::asString);
复制代码

随着 Spring boot 3.x 的推进,更多项目将会升级到 java17,那么 jdk11 开始自带的这个 HttpClient 将会是 sdk 开发和中间件开发最佳选择。


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-4-20 21:31 , Processed in 0.014281 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表