這篇文章主要介紹Go語言中http/2服務(wù)器功能是什么,文中介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們一定要看完!
大興ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場景,ssl證書未來市場廣闊!成為成都創(chuàng)新互聯(lián)公司的ssl證書銷售渠道,可以享受市場價格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:028-86922220(備注:SSL證書合作)期待與您的合作!
HTTP/2 服務(wù)器
首先,讓我們在Go中創(chuàng)建一個http/2服務(wù)器!根據(jù)http/2文檔,所有東西都是為我們自動配置的,我們甚至不需要導(dǎo)入Go的標(biāo)準(zhǔn)庫http2包:
HTTP/2強制使用TLS。為了實現(xiàn)這一點,我們首先需要一個私鑰和一個證書。在Linux上,下面的命令執(zhí)行這個任務(wù)。
openssl req -newkey rsa:2048 -nodes -keyout server.key -x509 -days 365 -out server.crt
該命令將生成兩個文件:server.key 以及 server.crt
現(xiàn)在,對于服務(wù)器代碼,以最簡單的形式,我們將使用Go的標(biāo)準(zhǔn)庫HTTP服務(wù)器,并啟用TLS與生成的SSL文件。
package main import ( "log" "net/http" ) func main() { // 在 8000 端口啟動服務(wù)器 // 確切地說,如何運行HTTP/1.1服務(wù)器。 srv := &http.Server{Addr:":8000", Handler: http.HandlerFunc(handle)} // 用TLS啟動服務(wù)器,因為我們運行的是http/2,它必須是與TLS一起運行。 // 確切地說,如何使用TLS連接運行HTTP/1.1服務(wù)器。 log.Printf("Serving on https://0.0.0.0:8000") log.Fatal(srv.ListenAndServeTLS("server.crt", "server.key")) } func handle(w http.ResponseWriter, r *http.Request) { // 記錄請求協(xié)議 log.Printf("Got connection: %s", r.Proto) // 向客戶發(fā)送一條消息 w.Write([]byte("Hello")) }
HTTP/2 客戶端
在go中,標(biāo)準(zhǔn) http.Client 也用于http/2請求。惟一的區(qū)別是在客戶端的Transport字段,使用 http2.Transport 代替 http.Transport。
我們生成的服務(wù)器證書是“自簽名”的,這意味著它不是由一個已知的證書頒發(fā)機構(gòu)(CA)簽署的。這將導(dǎo)致我們的客戶端不相信它:
package main import ( "fmt" "net/http" ) const url = "https://localhost:8000" func main() { _, err := http.Get(url) fmt.Println(err) }
讓我們試著運行它:
$ go run h3-client.go Get https://localhost:8000: x509: certificate signed by unknown authority
在服務(wù)器日志中,我們還將看到客戶端(遠(yuǎn)程)有一個錯誤:
http: TLS handshake error from [::1]:58228: remote error: tls: bad certificate
為了解決這個問題,我們可以用定制的TLS配置去配置我們的客戶端。我們將把服務(wù)器證書文件添加到客戶端“證書池”中,因為我們信任它,即使它不是由已知CA簽名的。
我們還將添加一個選項,根據(jù)命令行標(biāo)志在HTTP/1.1和HTTP/2傳輸之間進(jìn)行選擇。
package main import ( "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) ) }
這一次我們得到了正確的回應(yīng):
$ go run h3-client.go Got response 200: HTTP/2.0 Hello
在服務(wù)器日志中,我們將看到正確的日志線:獲得連接:Got connection: HTTP/2.0!!
但是當(dāng)我們嘗試使用HTTP/1.1傳輸時,會發(fā)生什么呢?
$ go run h3-client.go -version 1 Got response 200: HTTP/1.1 Hello
我們的服務(wù)器對HTTP/2沒有任何特定的東西,所以它支持HTTP/1.1連接。這對于向后兼容性很重要。此外,服務(wù)器日志表明連接是HTTP/1.1:Got connection: HTTP/1.1。
HTTP/2 高級特性
我們創(chuàng)建了一個HTTP/2客戶機-服務(wù)器連接,并且我們正在享受安全有效的連接帶來的好處。但是HTTP/2提供了更多的特性,讓我們來研究它們!
服務(wù)器推送
HTTP/2允許服務(wù)器推送“使用給定的目標(biāo)構(gòu)造一個合成請求”。
這可以很容易地在服務(wù)器處理程序中實現(xiàn)(在github上的視圖):
func handle(w http.ResponseWriter, r *http.Request) { // Log the request protocol log.Printf("Got connection: %s", r.Proto) // Handle 2nd request, must be before push to prevent recursive calls. // Don't worry - Go protect us from recursive push by panicking. if r.URL.Path == "/2nd" { log.Println("Handling 2nd") w.Write([]byte("Hello Again!")) return } // Handle 1st request log.Println("Handling 1st") // Server push must be before response body is being written. // In order to check if the connection supports push, we should use // a type-assertion on the response writer. // If the connection does not support server push, or that the push // fails we just ignore it - server pushes are only here to improve // the performance for HTTP/2 clients. pusher, ok := w.(http.Pusher) if !ok { log.Println("Can't push to client") } else { err := pusher.Push("/2nd", nil) if err != nil { log.Printf("Failed push: %v", err) } } // Send response body w.Write([]byte("Hello")) }
使用服務(wù)器推送
讓我們重新運行服務(wù)器,并測試客戶機。
對于HTTP / 1.1客戶端:
$ go run ./h3-client.go -version 1 Got response 200: HTTP/1.1 Hello
服務(wù)器日志將顯示:
Got connection: HTTP/1.1Handling 1st
Can't push to client
HTTP/1.1客戶端傳輸連接產(chǎn)生一個 http.ResponseWriter 沒有實現(xiàn)http.Pusher,這是有道理的。在我們的服務(wù)器代碼中,我們可以選擇在這種客戶機的情況下該做什么。
對于HTTP/2客戶:
go run ./h3-client.go -version 2 Got response 200: HTTP/2.0 Hello
服務(wù)器日志將顯示:
Got connection: HTTP/2.0Handling 1st
Failed push: feature not supported
這很奇怪。我們的HTTP/2傳輸?shù)目蛻舳酥坏玫搅说谝粋€“Hello”響應(yīng)。日志表明連接實現(xiàn)了 http.Pusher 接口——但是一旦我們實際調(diào)用 Push() 函數(shù)——它就失敗了。
排查發(fā)現(xiàn),HTTP/2客戶端傳輸設(shè)置了一個HTTP/2設(shè)置標(biāo)志,表明推送是禁用的。
因此,目前沒有選擇使用Go客戶機來使用服務(wù)器推送。
作為一個附帶說明,google chrome作為一個客戶端可以處理服務(wù)器推送。
服務(wù)器日志將顯示我們所期望的,處理程序被調(diào)用兩次,路徑 / 和 /2nd,即使客戶實際上只對路徑 /:
Got connection: HTTP/2.0Handling 1st
Got connection: HTTP/2.0Handling 2nd
全雙工通信
Go HTTP/2演示頁面有一個echo示例,它演示了服務(wù)器和客戶機之間的全雙工通信。
讓我們先用CURL來測試一下:
$ curl -i -XPUT --http2 https://http2.golang.org/ECHO -d hello HTTP/2 200 content-type: text/plain; charset=utf-8 date: Tue, 24 Jul 2018 12:20:56 GMT HELLO
我們把curl配置為使用HTTP/2,并將一個PUT/ECHO發(fā)送給“hello”作為主體。服務(wù)器以“HELLO”作為主體返回一個HTTP/2 200響應(yīng)。但我們在這里沒有做任何復(fù)雜的事情,它看起來像是一個老式的HTTP/1.1半雙工通信,有不同的頭部。讓我們深入研究這個問題,并研究如何使用HTTP/2全雙工功能。
服務(wù)器實現(xiàn)
下面是HTTP echo處理程序的簡化版本(不使用響應(yīng))。它使用 http.Flusher 接口,HTTP/2添加到http.ResponseWriter。
type flushWriter struct { w io.Writer } func (fw flushWriter) Write(p []byte) (n int, err error) { n, err = fw.w.Write(p) // Flush - send the buffered written data to the client if f, ok := fw.w.(http.Flusher); ok { f.Flush() } return } func echoCapitalHandler(w http.ResponseWriter, r *http.Request) { // First flash response headers if f, ok := w.(http.Flusher); ok { f.Flush() } // Copy from the request body to the response writer and flush // (send to client) io.Copy(flushWriter{w: w}, r.Body) }
服務(wù)器將從請求正文讀取器復(fù)制到寫入ResponseWriter和 Flush() 的“沖洗寫入器”。同樣,我們看到了笨拙的類型斷言樣式實現(xiàn),沖洗操作將緩沖的數(shù)據(jù)發(fā)送給客戶機。
請注意,這是全雙工,服務(wù)器讀取一行,并在一個HTTP處理程序調(diào)用中重復(fù)寫入一行。
GO客戶端實現(xiàn)
我試圖弄清楚一個啟用了HTTP/2的go客戶端如何使用這個端點,并發(fā)現(xiàn)了這個Github問題。提出了類似于下面的代碼。
const url = "https://http2.golang.org/ECHO" func main() { // Create a pipe - an object that implements `io.Reader` and `io.Writer`. // Whatever is written to the writer part will be read by the reader part. pr, pw := io.Pipe() // Create an `http.Request` and set its body as the reader part of the // pipe - after sending the request, whatever will be written to the pipe, // will be sent as the request body. // This makes the request content dynamic, so we don't need to define it // before sending the request. req, err := http.NewRequest(http.MethodPut, url, ioutil.NopCloser(pr)) if err != nil { log.Fatal(err) } // Send the request resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } log.Printf("Got: %d", resp.StatusCode) // Run a loop which writes every second to the writer part of the pipe // the current time. go func() { for { time.Sleep(1 * time.Second) fmt.Fprintf(pw, "It is now %v\n", time.Now()) } }() // Copy the server's response to stdout. _, err = io.Copy(os.Stdout, res.Body) log.Fatal(err) }
以上是“Go語言中http/2服務(wù)器功能是什么”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對大家有幫助,更多相關(guān)知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!
網(wǎng)站題目:Go語言中http/2服務(wù)器功能是什么
文章分享:http://jinyejixie.com/article8/iephip.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供用戶體驗、品牌網(wǎng)站制作、外貿(mào)網(wǎng)站建設(shè)、動態(tài)網(wǎng)站、定制開發(fā)、云服務(wù)器
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)