在这个例子中,我们将创建一个基于TLS的HTTP/2服务器,并让客户端通过HTTP/2协议而不是传统的HTTP/1进行通信。
传统的HTTP/1通信是通过他们自己的连接进行的,所以每个连接有一个请求。这将是缓慢的,因为连接协商、TLS握手、TCP慢速启动策略等都是为每个请求而发生。解决这个问题的方法是使用HTTP/2协议。在HTTP/2通信的情况下,可以在一个连接上提出多个请求。这意味着连接协商、TLS握手、TCP慢速启动策略等只发生一次,从而提高了性能。这也取决于HTTP keep-alive功能,该功能默认是启用的,但在创建自定义传输时,你可能会意外地禁用它。除非你有理由禁用它(我无法想象你为什么要禁用),否则我建议你使用它。
另一个你可能意外地禁用连接重用的原因是在使用它时没有尽快关闭响应体。Pipelining允许多个请求和它们的响应以并行方式而不是串行方式进行通信。为了达到这个目的,你必须使用res.Body.Close() ,尽快关闭主体,而不是推迟它,这样下面的请求(如果有的话)就会使用现有的连接来提高整体性能。
记住
HTTP/2的性能优势来自于同时/并行(管道化)和批量请求。例如,根据我的测试,HTTP/2能够处理500,000个请求(30秒~),但HTTP/1只能勉强处理100个请求,并出现许多 "管道断裂"、"连接被对方重置 "的错误。这些测试是在goroutines中发出请求的。
超时
服务器
客户端
SSL
HTTP/2协议执行TLS,所以我们必须首先创建一个SSL密钥和一个SSL证书。让我们继续创建自签名的私钥和公钥对。
私钥
这将只用于服务器。
$ openssl genrsa -out cert/private.key 4096
公共证书
这将同时用于服务器和客户端。
$ openssl req -new -x509 -sha256 -days 1825 -key cert/private.key -out cert/public.crt
上面的Common Name 字段是非常重要的。如果你输入的内容与你的客户使用的请求主机/URL或tls.Config.ServerName 的一部分不一致,你将得到以下错误之一。
// Client side errors.
服务器
结构
.
main.go
package main
运行
运行,等待客户端的请求,并对其作出回应。
$ go run -race cmd/server/main.go
客户端
结构
.
main.go
运行go get -u golang.org/x/net/http2 ,安装HTTP/2包。如下图所示,我注释了transport1 函数,它依赖于默认的http 包。它告诉我们如何创建一个HTTP/2传输。从技术上讲,transport1 和transport2 请求的结果是相同的,如下图所示。
package main
运行
$ go run -race cmd/client/main.go