1. 程式人生 > >Golang使用HTTP/2的正確方法

Golang使用HTTP/2的正確方法

golang在http/2這塊做的比較早,但是因為歷史原因導致API比較令人迷惑,網上很多同學在抱怨。

我這裡記錄一下如何正確的實施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