在 go 中, 标准 http.Client 也用于 http/2 请求. 惟一的区别是在客户端的 Transport 字段, 使用 http2.Transport 代替 http.Transport.
我们生成的服务器证书是 "自签名" 的, 这意味着它不是由一个已知的证书颁发机构 (CA) 签署的. 这将导致我们的客户端不相信它:
- package mainimport ( "fmt" "net/http")const url = "https://localhost:8000"func main() {
- _, err := http.Get(url) fmt.Println(err)
- }
让我们试着运行它:
- $ go run h2-client.go
- Get https://localhost:8000: x509: certificate signed by unknown authority
在服务器日志中, 我们还将看到客户端 (远程) 有一个错误:
http: TLS handshake error from [::1]:58228: remote error: tls: bad certificate
为了解决这个问题, 我们可以用定制的 TLS 配置去配置我们的客户端. 我们将把服务器证书文件添加到客户端 "证书池" 中, 因为我们信任它, 即使它不是由已知 CA 签名的.
我们还将添加一个选项, 根据命令行标志在 HTTP/1.1 和 HTTP/2 传输之间进行选择.
- package mainimport ( "crypto/tls"
- "crypto/x509"
- "flag"
- "fmt"
- "io/ioutil"
- "log"
- "net/http"
- "golang.org/x/net/http2") const url = "https://localhost:8000"var httpVersion = flag.Int("version", 2, "HTTP version")
- func main() {
- flag.Parse()
- client := &http.Client{} // Create a pool with the server certificate since it is not signed
- // by a known CA
- caCert, err := ioutil.ReadFile("server.crt") if err != nil { log.Fatalf("Reading server certificate: %s", err)
- }
- caCertPool := x509.NewCertPool()
- caCertPool.AppendCertsFromPEM(caCert) // Create TLS configuration with the certificate of the server
- tlsConfig := &tls.Config{
- RootCAs: caCertPool,
- }
- // Use the proper transport in the client
- switch *httpVersion { case 1:
- client.Transport = &http.Transport{
- TLSClientConfig: tlsConfig,
- } case 2:
- client.Transport = &http2.Transport{
- TLSClientConfig: tlsConfig,
- }
- } // Perform the request
- resp, err := client.Get(url)
- if err != nil { log.Fatalf("Failed get: %s", err)
- }
- defer resp.Body.Close()
- body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatalf("Failed reading response body: %s", err)
- }
- fmt.Printf( "Got response %d: %s %s\n",
- resp.StatusCode, resp.Proto, string(body) )
- }
这一次我们得到了正确的回应:
- $ go run h2-client.go
- Got response 200: HTTP/2.0 Hello
在服务器日志中, 我们将看到正确的日志线: 获得连接: Got connection: HTTP/2.0! ! 但是当我们尝试使用 HTTP/1.1 传输时, 会发生什么呢?
- $ go run h2-client.go -version 1
- Got response 200: HTTP/1.1 Hello
我们的服务器对 HTTP/2 没有任何特定的东西, 所以它支持 HTTP/1.1 连接. 这对于向后兼容性很重要. 此外, 服务器日志表明连接是 HTTP/1.1:Got connection: HTTP/1.1.
来源: https://juejin.im/entry/5b98ededf265da0a972e0783