Tomcat9配置HTTP2

29次阅读

共计 4048 个字符,预计需要花费 11 分钟才能阅读完成。

1 概述

Tomcat 从 Tomcat8 的一些较新版本就支持 HTTP/ 2 了,Tomcat9 直接支持,本文首先讲述了相关 HTTP/ 2 的特性,接着利用一个简单的开源工具 mkcert 生成证书并利用该证书配置 HTTP/2。

2 HTTP/ 2 特性

首先介绍一下 HTTP/ 2 特性,这也从另一方面解释了为什么需要使用 HTTP/2。

2.1 二进制分帧

HTTP/ 2 在应用层与传输层增加了一个二进制分帧,能够达到“在不改动 HTTP 语义,HTTP 方法,状态码,URI 及首部字段的情况下,突破 HTTP/1.1 的性能限制,改进传输性能,实现低延迟和高吞吐量。”

2.2 压缩头部

HTTP/ 2 对消息头采用了 HPACK 进行压缩传输,能够节省消息头占用的网络流量,而 HTTP/1.x 每次请求都会携带大量的冗余头信息,浪费了很多带宽资源。

2.3 多路复用

简单地说就是所有的请求都通过一个 TCP 连接并发完成。HTTP/1.x 虽然能利用一个连接完成多次请求,但是多个请求之间是有先后顺序的,后面发送的请求必须等待上一个请求返回才能发送响应,很容易导致后面的请求被阻塞。而 HTTP/ 2 做到了真正的并发请求。
HTTP/ 2 将消息分解为帧,为每帧分配一个流标识符,然后在一个 TCP 连接上独立发送,HTTP/ 2 将请求帧与响应帧交织在一起,能够让所有请求与响应都在一个套接字上发生,所有请求或响应都无法相互阻塞,减少了延迟,提高了页面加载速度,消除了对 HTTP/1.1 工具的需求。

2.4 流优先及流控制

消息帧通过对流进行发送,每个流分配了一个优先级,用于确定处理顺序以及收到的资源量,优先级可以是 0 -256 之间的数字,可以定义依赖关系,允许在一个资源之前加载另一个资源。
流控制管理数据的传输,允许接收者停止或减少发送的数据量,比如观看视频暂停时,客户端会通知服务器停止发送视频数据。

2.5 服务器推送

一般情况下需要客户端请求服务器才会响应,HTTP/ 2 中能够先于客户端检测将要请求的资源,提前通知客户端,但是不发送资源只发送 URL,客户端收到后会进行验证缓存,发现需要则正式发起请求。

2.6 应用层协商协议

客户端与服务器都升级才能支持 HTTP/2,但是有可能存在 HTTP/ 1 与 HTTP/ 2 并存的情况,如果都使用 80 端口,需要选择其中一个协议通信。
APLN(Application Layer Protocol Negotiation)就是为了解决这个问题,通过协商选择协议:

  • 首先客户端发起请求,如果支持 HTTP/ 2 则带 upgrade 头部
  • 若服务器不支持则拒绝升级通过 HTTP/1.1 返回响应
  • 若服务器支持则接受升级,切换到新分帧使用 HTTP/ 2 通信

更多请查看 RFC7540 官方文档。

3 使用 mkcert 生成证书

网上大部分的教程都是使用 OpenSSL 生成根证书,客户端证书以及服务端证书的,一堆参数配置非常复杂,因此这里使用一个简单的一键生成本地证书的开源工具 mkcert,无需任何配置。

3.1 安装 mkcert

3.1.1 MacOS

brew install mkcert
brew install nss # 如果使用火狐

使用 MacPorts:

sudo port selftupdate
sudo port install mkcert
sudo port install css # 如果使用火狐

3.1.2 Linux

需要先安装certutil

#Debian/Ubuntu
sudo apt install libnss3-tools
#Red Hat/Fedora/CentOS
sudo yum install nss-tools
#Arch/Manjaro
sudo pacman -S nss
#SUSE
sudo zypper install mozilla-nss-tools

使用 LinuxBrew 安装:

brew install mkcert

安装 LinuxBrew:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"

Arch/Manjaro 可以使用 pacman 安装:

sudo pacman -Syu mkcert

或者从源码安装(需要 go 环境):

git clone https://github.com/FiloSottile/mkcert && cd mkcert
go build -ldflags "-X main.Version=$(git describe --tags)"

或者使用已构建好的版本。

3.1.3 Windows

安装 Chocolatey(以管理员运行 PowerShell):

Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))

或安装 Scoop(管理员 PowerShell):

Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh')
# 或
iwr -useb get.scoop.sh | iex

使用 Chocolatey 或 Scoop 安装:

choco install mkcert
#或
scoop bucket add extras
scoop install mkcert

或者使用已构建好的版本。

3.2 生成证书

mkcert 的命令非常简单,可以使用 --help 查看帮助:

mkcert --help

3.2.1 安装本地 CA 证书

mkcert -install

默认会在 ~/.local/share/mkcert 生成 CA 证书。

3.2.2 利用 CA 证书签发本地证书

mkcert localhost

其中 localhost 表示签发本地证书,可以换成 example.com*.example.comexample.test127.0.0.1::1 之类的域名或者 ip。
执行后会在当前文件夹下生成 localhost-key.pemlocalhost.pem,前者是私钥,后者是证书。

4 配置 Tomcat

Tomcat 可以通过两种方式配置 HTTP/2,一种是自带的 Nio 方式,另一种是使用额外库 APR,APR-util 与 TC-Native 的方式。

4.1 使用 Nio

通过 Nio 配置 HTTP/ 2 需要结合 OpenSSL 与 keytool 将证书转换为 pkcs#12 再转换为jks

openssl pkcs12 -export -inkey localhost-key.pem -in localhost.pem -out localhost.p12

会提示输入导出密码,需要记住,转换成 jks 时需要用到。

接着转换为jks

keytool -importkeystore -srckeystore localhost.p12 -srcstoretype pkcs12 -destkeystore localhost.jks

这里会提示输入目标 keystore 与源 keystore 的密码,目标 keystore 密码一会在修改 server.xml 时需要用到,源 keystore 密码就是上面的导出密码。

接着复制 localhost.jks 到 Tomcat 的 conf 下并修改server.xml

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
               maxThreads="150" SSLEnabled="true">
    <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
    <SSLHostConfig>
        <Certificate certificateKeystoreFile="conf/localhost.jks"
                        certificateKeystorePassword="111111"
                     type="RSA" />
    </SSLHostConfig>
</Connector>

添加了升级协议(默认 HTTP/1.1):

<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />

另外 certificateKeystorePassword 是上一步的目标 keystore 的密码。
完成后开启 Tomcat 并访问https://localhost:8443

4.2 使用 APR

使用 APR 不需要对证书进行额外的转换,但是需要安装三个库:

  • APR
  • APR-util
  • TC-Native

笔者的 Manjaro 可以直接包管理器安装:

sudo pacman -S apr apr-util tomcat-native

其他系统请自行使用包管理器或者按上面的官网链接进行编译安装。
复制 localhost-key.pemlocalhost.pem到 Tomcat 的 conf 目录下,并修改server.xml

<Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol"
               maxThreads="150" SSLEnabled="true" >
    <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
    <SSLHostConfig>
        <Certificate certificateKeyFile="conf/localhost-key.pem"
                     certificateFile="conf/localhost.pem"
                     type="RSA" />
    </SSLHostConfig>
</Connector>

开启 Tomcat 后就可以访问 https://localhost:8443 了:

正文完
 0