我這里記錄一下如何正確的實施HTTP/2的客戶端與服務端。
HTTP/2協議
HTTP/2協議握手分2種方式,一種叫h2,一種叫h2c。
h2要求必須使用TLS加密,在TLS握手期間會順帶完成HTTPS/2協議的協商,如果協商失敗(比如客戶端不支持或者服務端不支持),則會使用HTTPS/1繼續后續通訊。
h2c不使用TLS,而是多了一次基於HTTP協議的握手往返來完成向HTTP/2協議的升級,一般不建議使用。
GO標准庫
GO的http庫默認支持HTTP/2協議,只要我們使用TLS則會默認啟動HTTP/2特性。
http庫在設計API時並沒有支持用戶使用h2c,而是鼓勵使用h2。
只要我們使用TLS,則http庫就會默認進行HTTPS/2協商,協商失敗則蛻化為HTTPS/1。
讓很多開發者迷惑的點在於,當我們希望對http Client或者Server做一些更加定制化的配置時,就會覆蓋掉http庫的默認行為,從而導致無法啟用HTTP/2協議。
下面我就會告訴大家,到底怎么保證HTTP/2協議的啟用。
服務端
我們明確一定要用h2模式,也就是犧牲TLS加密的時間,但是換來的就是HTTP/2的使用便捷性。
制作證書
我們首先需要為服務端制作證書和私鑰,其中證書會在收到請求時發回給客戶端。
證書是我們自簽的,沒有第三方CA作驗證,所以客戶端需要關閉校驗證書有效性的特性。
1,生成服務端私鑰 openssl genrsa -out default.key 2048 2,生成服務端證書 openssl req -new -x509 -key default.key -out default.pem -days 3650
default.key是私鑰,default.pem是證書。
校驗證書
因為我們是X509格式簽名的證書,所以程序做好先做一下有效性校驗:
// TLS證書解析驗證 if _, err = tls.LoadX509KeyPair(G_config.ServerPem, G_config.ServerKey); err != nil { return common.ERR_CERT_INVALID }
確認證書有效后,我們最終通過serverTLS傳入證書和私鑰,啟動一個HTTPS/2服務:
// HTTP/2 TLS服務 server = &http.Server{ ReadTimeout: time.Duration(G_config.ServiceReadTimeout) * time.Millisecond, WriteTimeout: time.Duration(G_config.ServiceWriteTimeout) * time.Millisecond, Handler: mux, } // 監聽端口 if listener, err = net.Listen("tcp", ":" + strconv.Itoa(G_config.ServicePort)); err != nil { return } // 拉起服務 go server.ServeTLS(listener, G_config.ServerPem, G_config.ServerKey)
除了使用ServeTLS來啟動支持HTTPS/2特性的服務端之外,還可以通過http2.ConfigureServer來為http.Server啟動HTTPS/2特性並直接使用Serve來啟動服務。
客戶端
客戶端最重要的是配置Transport,所謂Transport就是底層的連接管理器,包括了協議的處理能力。
因為我們有很多定制化Client配置的需求,所以我們自己生成了一個Transport而不是內置的Transport:
transport = &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true,}, // 不校驗服務端證書 MaxIdleConns: G_config.GatewayMaxConnection, MaxIdleConnsPerHost: G_config.GatewayMaxConnection, IdleConnTimeout: time.Duration(G_config.GatewayIdleTimeout) * time.Second, // 連接空閑超時 }
其中TLS配置聲明了InsecureSkipVerify=true,表示不向CA校驗證書的有效性。
類似於服務端,因為我們沒有使用內置的Client Transport,所以我們需要使用http2.ConfigureTransport來啟動HTTPS/2特性:
// 啟動HTTP/2協議 http2.ConfigureTransport(transport)
最后將Transport配置給Client,負責底層的連接與協議管理:
// HTTP/2 客戶端 gateConn.client = &http.Client{ Transport: transport, Timeout: time.Duration(G_config.GatewayTimeout) * time.Millisecond, // 請求超時 }
最后
首先理解h2和h2c的區別,然后明確Go語言推薦使用h2。
最后,當我們沒有使用默認的http配置時,我們需要通過http2.ConfigureXXX重新配置啟用HTTP2/S特性。
來源:http://www.imooc.com/article/details/id/78928