JDK HTTP Client 介绍

作者: Chris Hegarty +
译者: qunfanyi.com
英文原文:https://developer.oracle.com/java/jdk-http-client

JDK HTTP客户端是在JDK 9中添加的。它可以用于通过网络请求HTTP资源。它支持 HTTP/1.1和HTTP/2 ,也支持同步和异步编程模型,将请求和响应体作为反应流处理,并遵循熟悉的构建器模式。这是一个基本的请求,它将响应体打印为字符串。

    HttpClient client = HttpClient.newHttpClient();
    HttpRequest request = HttpRequest.newBuilder()
          .uri(URI.create("http://openjdk.java.net/"))
          .build();
    client.sendAsync(request, asString())
          .thenApply(HttpResponse::body)
          .thenAccept(System.out::println)
          .join();

孵化(译者:此节已经成为历史)

(译者:2018年9月已经在 JDK 11 正式发布)
JDK11 中已经是正式标准化了
API目前有一个孵化状态,反映在它的模块和包名中。 其目的是在将来的Java SE版本中孵育API,然后将其移动到标准化。More information on incubation can be found in JEP 11, but for now it's sufficient to recognise the package name, and know how to get access to the API by specifying its containing module, jdk.incubator.httpclient, to the --add-modules command line option. The Maven compiler and surefire plugins can be configured as follows:
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
                <configuration>
                    <source>9</source>
                    <target>9</target>
                    <compilerArgument>--add-modules=jdk.incubator.httpclient</compilerArgument>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.20.1</version>
                <configuration>
                    <argLine>--add-modules=jdk.incubator.httpclient</argLine>
                </configuration>
            </plugin>
        </plugins>
    </build>

HttpClient

要发送一个请求,先用 Builder 创建一个 HttpClient 。

Builder 可以用于配置每个 client 的状态,如:

  • 合适的协议版本 ( HTTP/1.1 or HTTP/2 )

  • 如何处理重定向

  • 网络代理

  • 授权处理

    HttpClient client = HttpClient.newBuilder()
          .version(Version.HTTP_2)
          .followRedirects(Redirect.SAME_PROTOCOL)
          .proxy(ProxySelector.of(new InetSocketAddress("www-proxy.com", 8080)))
          .authenticator(Authenticator.getDefault())
          .build();

build() 返回的 HttpClient 可以发送多个 requests 。 == HttpRequest

HttpRequest 从它的 builder 创建。request builder 可以用于设置:

  • 请求的网址

  • 请求的方法(GET、PUT、POST)

  • 请求的内容(如果有的话)

  • 超时时长

  • 请求头

    HttpRequest request = HttpRequest.newBuilder()
          .uri(URI.create("http://openjdk.java.net/"))
          .timeout(Duration.ofMinutes(1))
          .header("Content-Type", "application/json")
          .POST(BodyPublisher.fromFile(Paths.get("file.json")))
          .build()

build() 返回的 HttpRequest 是不可以修改的,但是可以发送多次。

同步或异步

请求可以同步或异步发送。正如预期的那样,同步API 直到 HttpResponse 可用后才返回。

    HttpResponse<String> response = client.send(request, BodyHandler.asString());
    System.out.println(response.statusCode());
    System.out.println(response.body());

异步 API 立即返回一个 CompletableFuture,当 HttpResponse 可用时,会调用 completableFuture.complete(httpResponse) 。CompletableFuture 是Java 8 中添加的,支持复合异步编程。

    client.sendAsync(request, BodyHandler.asString())
          .thenApply(response -> { System.out.println(response.statusCode());
                                   return response; } )
          .thenApply(HttpResponse::body)
          .thenAccept(System.out::println);

响应流式数据

请求和响应主体作为公开响应流(非阻塞背压式的异步数据流)。HttpClient 实际上是请求主体的 Subscriber 和响应主体字节的 Publisher。BodyHandler 接口允许在收到实际响应主体之前检查响应代码和头部,并负责创建响应BodySubscriber。

    public abstract class HttpRequest {
        ...
        public interface BodyPublisher
                    extends Flow.Publisher<ByteBuffer> { ... }
    }
    public abstract class HttpResponse<T> {
        ...
        public interface BodyHandler<T> {
            BodySubscriber<T> apply(int statusCode, HttpHeaders responseHeaders);
        }
        public interface BodySubscriber<T>
                    extends Flow.Subscriber<List<ByteBuffer>> { ... }
    }

HttpRequest 和HttpResponse 类型提供了许多方便的工厂方法,用于创建处理常见的主体类型(如文件、字符串和字节)的请求发布者和响应订阅者。这些便捷的实现可以用于累积像字符串这种数据直到可以创建更高级 Java 类型,也可以形成数据流如文件。BodySubscriber 及 BodyPublisher 可以用于定制响应流数据处理。

    HttpRequest.BodyPublisher::fromByteArray(byte[])
    HttpRequest.BodyPublisher::fromByteArrays(Iterable)
    HttpRequest.BodyPublisher::fromFile(Path)
    HttpRequest.BodyPublisher::fromString(String)
    HttpRequest.BodyPublisher::fromInputStream(Supplier< InputStream>)
    HttpResponse.BodyHandler::asByteArray()
    HttpResponse.BodyHandler::asString()
    HttpResponse.BodyHandler::asFile(Path)
    HttpResponse.BodyHandler::discard()

java.util.concurrent.Flow 的 Publisher/Subscriber 与 HTTP Client 的 BodyPublisher/BodySubscriber 之间的类型适配器已经在 JDK 10 中增加,更多细节参考 JDK-8193366。

HTTP/2

JDK HTTP 客户端同时支持 HTTP/1.1和HTTP/ 2。默认情况下,客户端将使用HTTP/2发送请求。发送到不支持HTTP/2的服务器将自动降级为HTTP/1.1。下面是HTTP/2带来的主要改进的总结:

  • Http headers 压缩。

  • HTTP/2使用HPACK压缩,这减少了开销。

  • 只有一个连接到服务器,减少了为建立多个TCP连接所需的往返次数。

  • 多路复用。

  • 在同一时间,在同一连接上允许多个请求。

  • 服务端推送。

  • 可以把将来额外需要的资源发送给客户端。

  • 二进制格式。

  • 更紧凑。

由于HTTP/2是默认的首选协议,并且支持在必要时无缝地回退到HTTP/1.1,因此JDK HTTP客户端在将来部署 HTTP/2 更广泛的时候更有利。 == 未来(译者:已经是现实了)

社区对孵化 JDK HTTP Client 的反馈的结果已经更新到 JDK 10。更多便捷 request body publishers 及 response body subscribers 都已经增加。该实现已被改写为完全异步的。JEP 321 已经被提交到 JavaSE 标准化 HTTP Client。这意味着,jdk.incubator 模块和包前缀将被删除,会直接使用 java.net 包。不再需要额外的 --add-modules 命令行选项(默认就可以使用)。 == 参考

JDK 9中的JDK HTTP客户端文档
最新JDK 10 中的JDK HTTP客户端文档

数码
沪ICP备19006215号-4