Spring Boot 启用 http2 协议

王大爷 2021年08月04日 992次浏览

Spring Boot 启用 http2 协议

HTTP2是万维网(WWW)发布的HTTP网络协议主流版本,也是当前HTTP协议的最新版本(1997年发布的HTTP 1.1)。它来源于SPDY协议,最初由谷歌开发。

1. HTTP2的优势

所有主流的浏览器,如Chrome, Opera, Firefox, Safari, Edge浏览器都支持这个协议。相对于HTTP1.1协议,HTTP2的优势主要包括下面几点。
在这里插入图片描述

1.1 多路复用和并发性

一般渲染HTML页面可能需要JS, CSS,图像等多个资源文件,需要从服务器获取资源从而获得更好的界面体验。使用HTTP1.1协议,HTML响应客户端每个JS, CSS,单独图像文件的请求,每个都需要一个TCP连接请求,需要占用昂贵的服务器和网络资源。

在HTTP2协议中有所改进,不再是客户端在单个HTML页面中请求多个所需的资源。服务器通过一个TCP连接将页面中所需响应推送给客户端,这样服务器提供必要的数据给浏览器渲染页面,浏览器无需等待第一个响应。
在这里插入图片描述

1.2 流优先级

客户端可以指示对服务器来说哪些资源比其他资源更重要。为了提供资源优先级,HTTP2标准有个特性来提供相关的资源权重和依赖关系(如果流依赖于另一个流)。

  1. 每个流可以分配1-256之间的整数权重。

  2. 每个流可以提供对其他流的显式依赖。

  3. 依赖关系和权重的结合将允许客户端构造优先级树,该树表示客户端希望如何接收资源的偏好。服务器将使用这些信息对流处理进行优先级排序,并控制系统资源,如CPU、内存和其他资源,一旦响应可用,它将分配带宽以确保向客户端交付高优先级响应。

为了加快页面加载时间,所有新的浏览器基于资源类型,其在页面中位置,甚至参考以前访问优先级的经验值排列请求优先级,如果在之前访问的渲染中某个资源被阻塞,则同样资源在未来的请求可能会被优先考虑。

1.3 头部压缩

每个HTTP传输携带一组头信息,描述传输资源及其属性。在HTTP1.1协议中,所有的头部属性值以明文格式发送,每个请求将占用500-800字节,如果使用HTTP cookie,大小还会增加。HTTP2通过使用HPACK压缩格式技术提供了更好的解决方案,描述如下:

  1. 传输的头部字段通过静态霍夫曼编码,大大减少了传输大小。

  2. 它还需要服务器和客户端维护和更新以前发送的头部字段索引列表,然后使用它作为参考来有效地编码以前传输的值。霍夫曼提供了传输时要压缩的特定值,而传输前的索引列表使我们能够通过传输索引值对重复值进行编码,这些索引值可用于有效地查找和重新构建完整的头部键和值。
    在这里插入图片描述

1.4 服务器推送

服务器将把所有未被请求的依赖资源推送给客户端。
在这里插入图片描述

1.5 流控制

流控制机制来阻止发送方给接收方发送过多数据,有很多原因会导致可能无法处理这些过量数据,如接收方在负载较重的情况下无法响应,或者没有足够的缓冲空间去处理数据。

HTTP2通过提供接收窗口(rwnd)解决了这些问题,窗口设定通信发送方和接收方之间传输数据的大小。当第一次建立连接时,它将使用默认设置。如果在下载文件时,服务器正向客户端流传输大量数据,此时接收窗口可能会成为限制因子;类似的,当客户端向服务器发送大量数据时,服务器接收窗口将成为限制因子。无论怎样,窗口大小越小则限制越大。

如果窗口为零,则表明不能再发送数据,除非应用清除缓冲区中已有数据。这种流程机制适用在连接整个生命周期中持续运行的每个TCP连接:每个请求包都有两端最新的RW值,根据发送方和接收方的状态以及进程速度动态地切换数据流速率。

HTTP/2不再支持HTTP 1.1的分块移位编码机制,因为它提供了自己的、更有效的数据流机制。
在这里插入图片描述

2. Spring Boot 配置

无需更改/更新任何Java应用程序或API来适用HTTP2协议,使用HTTP2可使Java应用程序工作得更好,在客户端和服务器上消耗资源更少。

2.1 tomcat 配置

只有Tomcat 9 版本之后版本才支持HTTP2协议。在 conf/server.xml 中增加内容:

<Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol" maxThreads="150" SSLEnabled="true">
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol"/>
<SSLHostConfig honorCipherOrder="false">
<Certificate certificateKeyFile="conf/ca.key" certificateFile="conf/ca.crt"/>
</SSLHostConfig>
</Connector>

2.2 Spring Boot配置(Springboot2.0 undertow http2.0)

对于Undertow 1.4.0+,如果使用Java 8,则无需任何额外配置即可支持HTTP2。

对于Jetty 9.4.11,如果使用Java 8,则还需要conscrypt类库,并需要依赖Jetty的如下两个模块:

  • org.eclipse.jetty:jetty-alpn-conscrypt-server
  • org.eclipse.jetty.http2:http2-server

对于Tomcat 9.0.x,如果使用Java 8,则还需要单独下载libtcnative类库>(使用其中的APR连接器,并设置升级协议为Http2Protocol),并在启动>Tomcat时加入JVM的启动参数如下:

-Djava.library.path=/usr/local/opt/tomcat-native/lib

对于Tomcat 9.0.x,如果使用Java 9,则无需任何额外配置即可支持HTTP2。

添加依赖

<dependency>
	<!--web 模块-->
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
    	<!--排除tomcat依赖-->
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<!-- undertow -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-undertow</artifactId>
</dependency>

制作证书

使用JDK自带的keytool,证书类型为:PKCS12。
执行下面命令,输入证书口令,执行完命令后会在执行的文件夹生成一个keystore.p12的文件,将keystore.p12拷贝到src/main/resources下。

keytool -genkey -alias undertow -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -dname "CN=localhost, OU=localhost, O=localhost, L=Zhengzhou, ST=Henan, C=CN"
输入密钥库口令:
再次输入新口令:

application.yaml配置

server:
#HTTP2.0 HTTPS端口号
  port: 8443
#自定义的HTTP1.1端口号
  http1.1:
    port: 8080
  compression:
    enabled: true
  http2:
    enabled: true
  ssl:
    enabled: true
    key-store: classpath:keystore.p12
    key-store-password: 123456
    key-store-type: PKCS12
    protocol: TLSv1.2
    key-alias: undertow
  undertow:
    io-threads: 2
    worker-threads: 36
    buffer-size: 1024
    directBuffers: true

添加HTTP支持

http2.0只支持https,如需同时使用http,则需添加下面配置

@Configuration
public class WebServerFactoryCustomizerConfig implements WebServerFactoryCustomizer<UndertowServletWebServerFactory> {
    @Value("${server.http1.1.port}")
    private int httpPort;

    /**
     * 自定义HTTP端口号
     *
     * @param factory
     */
    @Override
    public void customize(UndertowServletWebServerFactory factory) {
        factory.addBuilderCustomizers((UndertowBuilderCustomizer) builder -> {
            builder.addHttpListener(httpPort, "0.0.0.0");
        });
    }
}

服务启动后可以在控制台看到如下信息:
在这里插入图片描述

测试验证

编写测试用的请求处理器,然后在浏览器分别输入https://localhost:8443/http/infohttp://localhost:8080/http/info 进行验证。

@RestController
@RequestMapping("/http")
public class testController {
    @RequestMapping(value = "/info")
    public String info(HttpServletRequest request) {
        return request.getProtocol();
    }
}

在这里插入图片描述
在这里插入图片描述

2.3 http1.1 与http2.0 比较

浏览器访问:https://192.168.110.117:8443/someData

观察两次请求的size,一次是92一次是70,这是因为HTTP/2的头部压缩技术。

浏览器访问:http://localhost:8080/someData HTTP/1.1协议 而且数据包要比HTTP/2的数据包大,并且无论刷新多少次,大小是不变的。

3. 总结

本文介绍了HTTP2相对与HTTP1.1的主要特性,并说明如何配置Tomcat和Spring Boot以启用HTTP2协议。

经过比较http2协议,在http请求接口方面没有突出优势,在cdn请求上面有打较大优势。