在此章中,主要介绍以下内容:

  • 什么是HTTP/2 Client API

  • 如何创建HTTP客户端

  • 如何使HTTP请求

  • 如何接收HTTP响应

  • 如何创建WebSocket的endpoints

  • 如何将未经请求的数据从服务器推送到客户端

JDK 9将HTTP/2 Client API作为名为jdk.incubator.httpclient的孵化器模块。 该模块导出包含所有公共API的jdk.incubator.http包。 孵化器模块不是Java SE的一部分。 在Java SE 10中,它将被标准化,并成为Java SE 10的一部分,否则将被删除。 请参阅 http://openjdk.java.net/jeps/11上的网页,以了解有关JDK中孵化器模块的更多信息。

孵化器模块在编译时或运行时未被默认解析,因此需要使用--add-modules选项将jdk.incubator.httpclient模块添加到默认的根模块中,如下所示:

<javac|java|jmod...> -add-modules jdk.incubator.httpclient ...

如果另一个模块读取并解析了第二个模块,则也相应解析了孵化器模块。 在本章中,将创建一个读取jdk.incubator.httpclient模块的模块,不必使用-add-modules选项来解析。

因为孵化器模块提供的API还不是最终的,当在编译时或运行时使用孵化器模块时,会在标准错误上打印警告。 警告信息如下所示:

WARNING: Using incubator modules: jdk.incubator.httpclient

孵化器模块的名称和包含孵化器API的软件包以jdk.incubator开始。 一旦它们被标准化并包含在Java SE中,它们的名称将被更改为使用标准的Java命名约定。 例如,模块名称jdk.incubator.httpclient可能会在Java SE 10中成为java.httpclient。

因为jdk.incubator.httpclient模块不在Java SE中,所以将不会为此模块找到Javadoc。 为了生成此模块的Javadoc,并将其包含在本书的源代码中。 可以使用下载的源代码中的Java9Revealed/jdk.incubator.httpclient/dist/javadoc/index.html文件访问Javadoc。 使用JDK 9早期访问构建158的JDK版本来生成Javadoc。 API可能会改变,可能需要重新生成Javadoc。 以下是具体的步骤:

  1. 源代码包含与项目名称相同目录中的jdk.incubator.httpclient NetBeans项目。

  2. 安装JDK 9时,其源代码将作为src.zip文件复制到安装目录中。 将所有内容从src.zip文件中的jdk.incubator.httpclient目录复制到下载的源代码中的Java9revealed\jdk.incubator.httpclient\src目录中。

  3. 在NetBeans中打开jdk.incubator.httpclient项目。

  4. 右键单击NetBeans中的项目,然后选择“生成Javadoc”选项。 你会收到错误和警告,可以忽略。 它将在Java9Revealed/jdk.incubator.httpclient/dist/javadoc目录中生成Javadoc。 打开此目录中的index.html文件,查看jdk.incubator.httpclient模块的Javadoc。

一. 什么是HTTP/2 Client API?

自JDK 1.0以来,Java已经支持HTTP/1.1。 HTTP API由java.net包中的几种类型组成。 现有的API有以下问题:

  • 它被设计为支持多个协议,如http,ftp,gopher等,其中许多协议不再被使用。

  • 太抽象了,很难使用。

  • 它包含许多未公开的行为。

  • 它只支持一种模式,阻塞模式,这要求每个请求/响应有一个单独的线程。

2015年5月,IETF(Internet Engineering Task Force)发布了HTTP/2规范。 有关HTTP/2规范的完整文本,请访问https://tools.ietf.org/html/rfc7540。 HTTP/2不会修改应用程序级语义。 也就是说,对应用程序中的HTTP协议的了解和使用情况并没有改变。 它具有更有效的方式准备数据包,然后发送到客户端和服务器之间的电线。 所有之前知道的HTTP,如HTTP头,方法,状态码,URL等都保持不变。 HTTP/2尝试解决与HTTP/1连接所面临的许多性能相关的问题:

  • HTTP/2支持二进制数据交换,来代替HTTP/1.1支持的文本数据。

  • HTTP/2支持多路复用和并发,这意味着多个数据交换可以同时发生在TCP连接的两个方向上,而对请求的响应可以按顺序接收。 这消除了在对等体之间具有多个连接的开销,这在使用HTTP/1.1时通常是这种情况。 在HTTP/1.1中,必须按照发送请求的顺序接收响应,这称为head-of-line阻塞。 HTTP/2通过在同一TCP连接上进行复用来解决线路阻塞问题。

  • 客户端可以建议请求的优先级,服务器可以在对响应进行优先级排序时予以遵守。

  • HTTP首部(header)被压缩,这大大降低了首部大小,从而降低了延迟。

  • 它允许从服务器到客户端的资源推送。

JDK 9不是更新现有的HTTP/1.1 API,而是提供了一个支持HTTP/1.1和HTTP/2的HTTP/2 Client API。 该API旨在最终取代旧的API。 新API还包含使用WebSocket协议开发客户端应用程序的类和接口。 有关完整的WebSocket协议规范,请访问https://tools.ietf.org/html/rfc6455。 新的HTTP/2客户端API与现有的API相比有以下几个好处:

  • 在大多数常见情况下,学习和使用简单易用。

  • 它提供基于事件的通知。 例如,当收到首部信息,收到正文并发生错误时,会生成通知。

  • 它支持服务器推送,这允许服务器将资源推送到客户端,而客户端不需要明确的请求。 它使得与服务器的WebSocket通信设置变得简单。

  • 它支持HTTP/2和HTTPS/TLS协议。

  • 它同时工作在同步(阻塞模式)和异步(非阻塞模式)模式。

新的API由不到20种类型组成,其中有四种是主要类型。 当使用这四种类型时,会使用其他类型。 新API还使用旧API中的几种类型。 新的API位于jdk.incubator.httpclient模块中的jdk.incubator.http包中。 主要类型有三个抽象类和一个接口:

HttpClient classHttpRequest classHttpResponse classWebSocket interface

HttpClient类的实例是用于保存可用于多个HTTP请求的配置的容器,而不是为每个HTTP请求单独设置它们。 HttpRequest类的实例表示可以发送到服务器的HTTP请求。 HttpResponse类的实例表示HTTP响应。 WebSocket接口的实例表示一个WebSocket客户端。 可以使用Java EE 7 WebSocket API创建WebSocket服务器。

使用构建器创建HttpClientHttpRequestWebSocket的实例。 每个类型都包含一个名为Builder的嵌套类/接口,用于构建该类型的实例。 请注意,不用创建HttpResponse,它作为所做的HTTP请求的一部分返回。 新的HTTP/2 Client API非常简单,只需在一个语句中读取HTTP资源! 以下代码段使用GET请求,以URL https://www.google.com/作为字符串读取内容:

String responseBody = HttpClient.newHttpClient()
         .send(HttpRequest.newBuilder(new URI("https://www.google.com/"))
               .GET()
               .build(), BodyHandler.asString())
         .body();

处理HTTP请求的典型步骤如下:

  • 创建HTTP客户端对象以保存HTTP配置信息。

  • 创建HTTP请求对象并使用要发送到服务器的信息进行填充。

  • 将HTTP请求发送到服务器。

  • 接收来自服务器的HTTP响应对象作为响应。

  • 处理HTTP响应。

二. 设置案例

在本章中使用了许多涉及与Web服务器交互的例子。 不是使用部署在Internet上的Web应用程序,而是在NetBeans中创建了一个可以在本地部署的Web应用程序项目。 如果更喜欢使用其他Web应用程序,则需要更改示例中使用的URL。

NetBeans Web应用程序位于源代码的webapp目录中。 通过在GlassFish服务器4.1.1和Tomcat 8/9上部署Web应用程序来测试示例。 可以从https://netbeans.org/下载带有GlassFish服务器的NetBeans IDE。 在8080端口的GlassFish服务器上运行HTTP监听器。如果在另一个端口上运行HTTP监听器,则需要更改示例URL中的端口号。

本章的所有HTTP客户端程序都位于com.jdojo.http.client模块中,其声明如下所示。

// module-info.javamodule com.jdojo.http.client {
    requires jdk.incubator.httpclient;
}

三. 创建HTTP客户端

HTTP请求需要将配置信息发送到服务器,以便服务器知道要使用的身份验证器,SSL配置详细信息,要使用的cookie管理器,代理信息,服务器重定向请求时的重定向策略等。 HttpClient类的实例保存这些特定于请求的配置,它们可以重用于多个请求。 可以根据每个请求覆盖其中的一些配置。 发送HTTP请求时,需要指定将提供请求的配置信息的HttpClient对象。 HttpClient包含用于所有HTTP请求的以下信息:验证器,cookie管理器,执行器,重定向策略,请求优先级,代理选择器,SSL上下文,SSL参数和HTTP版本。

认证者是java.net.Authenticator类的实例。 它用于HTTP身份验证。 默认是不使用验证器。

Cookie管理器用于管理HTTP Cookie。 它是java.net.CookieManager类的一个实例。 默认是不使用cookie管理器。

执行器是java.util.concurrent.Executor接口的一个实例,用于发送和接收异步HTTP请求和响应。 如果未指定,则提供默认执行程序。

重定向策略是HttpClient.Redirect枚举的常量,它指定如何处理服务器的重定向问题。 默认值NEVER,这意味着服务器发出的重定向不会被遵循。

请求优先级是HTTP/2请求的默认优先级,可以在1到256(含)之间。 这是服务器优先处理请求的一个提示。 更高的值意味着更高的优先级。

代理选择器是java.net.ProxySelector类的一个实例,用于选择要使用的代理服务器。 默认是不使用代理服务器。

SSL上下文是提供安全套接字协议实现的javax.net.ssl.SSLContext类的实例。当不需要指定协议或不需要客户端身份验证时, 提供了一个默认的SSLContext,此选项将起作用。

SSL参数是SSL/TLS/DTLS连接的参数。 它们保存在javax.net.ssl.SSLParameters类的实例中。

HTTP版本是HTTP的版本,它是1.1或2.它被指定为HttpClient.Version枚举的常量:HTTP_1_1和HTTP_2。 它尽可能请求一个特定的HTTP协议版本。 默认值为HTTP_1_1。

Tips
HttpClient是不可变的。 当构建这样的请求时,存储在HttpClient中的一些配置可能会被HTTP请求覆盖。

HttpClient类是抽象的,不能直接创建它的对象。 有两种方法可以创建一个HttpClient对象:

  • 使用HttpClient类的newHttpClient()静态方法

  • 使用HttpClient.Builder类的build()方法

以下代码段获取默认的HttpClient对象:

// Get the default HttpClientHttpClient defaultClient = HttpClient.newHttpClient();

也可以使用HttpClient.Builder类创建HttpClient。 HttpClient.newBuilder()静态方法返回一个新的HttpClient.Builder类实例。 HttpClient.Builder类提供了设置每个配置值的方法。 配置的值被指定为方法的参数,该方法返回构建器对象本身的引用,因此可以链接多个方法。 最后,调用返回HttpClient对象的build()方法。 以下语句创建一个HttpClient,重定向策略设置为ALWAYS,HTTP版本设置为HTTP_2:

// Create a custom HttpClient
HttpClient httpClient = HttpClient.newBuilder()                      .followRedirects(HttpClient.Redirect.ALWAYS)
                      .version(HttpClient.Version.HTTP_2)
                      .build();

HttpClient类包含对应于每个配置设置的方法,该设置返回该配置的值。 这些方法如下:

Optional<Authenticator> authenticator()Optional<CookieManager> cookieManager()
Executor executor()
HttpClient.Redirect followRedirects()Optional<ProxySelector> proxy()
SSLContext sslContext()Optional<SSLParameters> sslParameters()
HttpClient.Version version()

请注意,HttpClient类中没有setter方法,因为它是不可变的。 不能使用HttpClient自己本身的对象。 在使用HttpClient对象向服务器发送请求之前,需要使用HttpRequest对象。HttpClient类包含以下三种向服务器发送请求的方法:

<T> HttpResponse<T> send(HttpRequest req, HttpResponse.BodyHandler<T> responseBodyHandler)<T> CompletableFuture<HttpResponse<T>> sendAsync(HttpRequest req, HttpResponse.BodyHandler<T> responseBodyHandler)<U,T> CompletableFuture<U> sendAsync(HttpRequest req, HttpResponse.MultiProcessor<U,T> multiProcessor)

send()方法同步发送请求,而sendAsync()方法异步发送请求。

四. 处理HTTP请求

客户端应用程序使用HTTP请求与Web服务器进行通信。 它向服务器发送一个请求,服务器发回对应的HTTP响应。 HttpRequest类的实例表示HTTP请求。 以下是处理HTTP请求所需执行的步骤:

  • 获取HTTP请求构建器(builder)

  • 设置请求的参数

  • 从构建器创建HTTP请求

  • 将HTTP请求同步或异步发送到服务器

  • 处理来自服务器的响应

1. 获取HTTP请求构建器

需要使用构建器对象,该对象是HttpRequest.Builder类的实例来创建一个HttpRequest。 可以使用HttpRequest类的以下静态方法获取HttpRequest.Builder

HttpRequest.Builder newBuilder()HttpRequest.Builder newBuilder(URI uri)

以下代码片段显示了如何使用这些方法来获取HttpRequest.Builder实例:

// A URI to point to googleURI googleUri = new URI("http://www.google.com");// Get a builder for the google URIHttpRequest.Builder builder1 = HttpRequest.newBuilder(googleUri);// Get a builder without specifying a URI at this timeHttpRequest.Builder builder2 = HttpRequest.newBuilder();

2. 设置HTTP请求参数

拥有HTTP请求构建器后,可以使用构建器的方法为请求设置不同的参数。 所有方法返回构建器本身,因此可以链接它们。 这些方法如下:

HttpRequest.Builder DELETE(HttpRequest.BodyProcessor body)
HttpRequest.Builder expectContinue(boolean enable)
HttpRequest.Builder GET()
HttpRequest.Builder header(String name, String value)
HttpRequest.Builder headers(String... headers)
HttpRequest.Builder method(String method, HttpRequest.BodyProcessor body)
HttpRequest.Builder POST(HttpRequest.BodyProcessor body)
HttpRequest.Builder PUT(HttpRequest.BodyProcessor body)
HttpRequest.Builder setHeader(String name, String value)
HttpRequest.Builder timeout(Duration duration)
HttpRequest.Builder uri(URI uri)
HttpRequest.Builder version(HttpClient.Version version)

使用HttpClientHttpRequest发送到服务器。 当构建HTTP请求时,可以使用version()方法通过HttpRequest.Builder对象设置HTTP版本值,该方法将在发送此请求时覆盖HttpClient中设置的HTTP版本。 以下代码片段将HTTP版本设置为2.0,以覆盖默认HttpClient对象中的NEVER的默认值:

// By default a client uses HTTP 1.1. All requests sent using this// HttpClient will use HTTP 1.1 unless overridden by the requestHttpClient client = HttpClient.newHttpClient();        
// A URI to point to googleURI googleUri = new URI("http://www.google.com");// Get an HttpRequest that uses HTTP 2.0HttpRequest request = HttpRequest.newBuilder(googleUri)
                                 .version(HttpClient.Version.HTTP_2)
                                 .build();// The client object contains HTTP version as 1.1 and the request// object contains HTTP version 2.0. The following statement will// send the request using HTTP 2.0, which is in the request object.HttpResponse<String> r = clie
                                 http://www.cnblogs.com/IcanFixIt/p/7229611.html

延伸阅读

向着Java前进-Java培训,做最负责任的教育,学习改变命运,软件学习,再就业,大学生如何就业,帮大学生找到好工作,lphotoshop培训,电脑培训,电脑维修培训,移动软件开发培训,网站设计培训,网站建设培训向着Java前进