以下由golang教學欄位介紹Go語言的http/2伺服器功能及客戶端使用,希望對需要的朋友有幫助!
前言
大家都知道,Go的標準函式庫HTTP伺服器預設支援HTTP/2。那麼,在這篇文章中,我們將首先展示Go的http/2伺服器功能,並解釋如何將它們作為客戶端使用。
在這篇文章中,我們將首先展示Go的http/2伺服器功能,並解釋如何將它們作為客戶端使用。 Go的標準庫HTTP伺服器預設支援HTTP/2。
下面話不多說了,來一起看看詳細的介紹吧
HTTP/2 伺服器
首先,讓我們在Go中建立一個http/2伺服器!根據http/2文檔,所有東西都是為我們自動配置的,我們甚至不需要導入Go的標準庫http2包:
HTTP/2強制使用TLS。為了實現這一點,我們首先需要一個私鑰和一個憑證。在Linux上,下面的指令執行這個任務。
openssl req -newkey rsa:2048 -nodes -keyout server.key -x509 -days 365 -out server.crt
該指令將產生兩個檔案:server.key 以及server.crt
#現在,對於伺服器程式碼,以最簡單的形式,我們將使用Go的標準庫HTTP伺服器,並啟用TLS與產生的SSL檔案。
package main import ( "log" "net/http" ) func main() { // 在 8000 端口启动服务器 // 确切地说,如何运行HTTP/1.1服务器。 srv := &http.Server{Addr:":8000", Handler: http.HandlerFunc(handle)} // 用TLS启动服务器,因为我们运行的是http/2,它必须是与TLS一起运行。 // 确切地说,如何使用TLS连接运行HTTP/1.1服务器。 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) { // 记录请求协议 log.Printf("Got connection: %s", r.Proto) // 向客户发送一条消息 w.Write([]byte("Hello")) }
HTTP/2 用戶端
#在go中,標準 http.Client 也用於http/2請求。惟一的差異是在客戶端的Transport字段,使用 http2.Transport 取代 http.Transport。
我們產生的伺服器憑證是「自簽署」的,這意味著它不是由一個已知的憑證授權單位(CA)簽署的。這將導致我們的客戶端不相信它:
package main import ( "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 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) ) }
這次我們得到了正確的回應:
$ 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。
HTTP/2 高級特性
我們創建了一個HTTP/2客戶機-伺服器連接,並且我們正在享受安全有效的連接帶來的好處。但是HTTP/2提供了更多的特性,讓我們來研究它們!
伺服器推送
HTTP/2允許伺服器推送「使用給定的目標建構一個合成請求」。
這可以很容易地在伺服器處理程序中實現(在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")) }
使用伺服器推送
##讓我們重新運行伺服器,並測試客戶機。 對於HTTP / 1.1客戶端:$ go run ./h2-client.go -version 1 Got response 200: HTTP/1.1 Hello伺服器日誌將顯示:
Got connection: HTTP/1.1Handling 1stHTTP/1.1客戶端傳輸連線產生一個http.ResponseWriter 沒有實作http.Pusher,這是有道理的。在我們的伺服器程式碼中,我們可以選擇在這種客戶機的情況下該做什麼。 對於HTTP/2客戶:Can't push to client
go run ./h2-client.go -version 2 Got response 200: HTTP/2.0 Hello伺服器日誌將顯示:
Got connection: HTTP/2.0Handling 1st這很奇怪。我們的HTTP/2傳輸的客戶端只得到了第一個「Hello」回應。日誌顯示連線實作了 http.Pusher 介面——但是一旦我們實際呼叫 Push() 函數——它就失敗了。 排查發現,HTTP/2客戶端傳輸設定了一個HTTP/2設定標誌,表示推送是停用的。 因此,目前沒有選擇使用Go客戶機來使用伺服器推送。 作為附帶說明,google chrome作為一個客戶端可以處理伺服器推送。Failed push: feature not supported
Got connection: HTTP/2.0Handling 1st
Got connection: HTTP/2.0Handling 2nd
全双工通信
Go HTTP/2演示页面有一个echo示例,它演示了服务器和客户机之间的全双工通信。
让我们先用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发送给“hello”作为主体。服务器以“HELLO”作为主体返回一个HTTP/2 200响应。但我们在这里没有做任何复杂的事情,它看起来像是一个老式的HTTP/1.1半双工通信,有不同的头部。让我们深入研究这个问题,并研究如何使用HTTP/2全双工功能。
服务器实现
下面是HTTP echo处理程序的简化版本(不使用响应)。它使用 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) }
服务器将从请求正文读取器复制到写入ResponseWriter和 Flush() 的“冲洗写入器”。同样,我们看到了笨拙的类型断言样式实现,冲洗操作将缓冲的数据发送给客户机。
请注意,这是全双工,服务器读取一行,并在一个HTTP处理程序调用中重复写入一行。
GO客户端实现
我试图弄清楚一个启用了HTTP/2的go客户端如何使用这个端点,并发现了这个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连接,这也支持HTTP/1.1与标准库的标准TLS服务器的连接——这太不可思议了。对于标准的库HTTP客户端,它不支持服务器推送,但是支持标准库的标准HTTP的全双工通信。以上就是本篇的内容,大家有什么疑问可以在文章下面留言沟通。
以上是關於Go語言的http/2伺服器功能及客戶端使用方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

go语言有缩进。在go语言中,缩进直接使用gofmt工具格式化即可(gofmt使用tab进行缩进);gofmt工具会以标准样式的缩进和垂直对齐方式对源代码进行格式化,甚至必要情况下注释也会重新格式化。

本篇文章带大家了解一下golang 的几种常用的基本数据类型,如整型,浮点型,字符,字符串,布尔型等,并介绍了一些常用的类型转换操作。

闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment,词法环境)的引用的组合。 换而言之,闭包让开发者可以从内部函数访问外部函数的作用域。 闭包会随着函数的创建而被同时创建。

go语言叫go的原因:想表达这门语言的运行速度、开发速度、学习速度(develop)都像gopher一样快。gopher是一种生活在加拿大的小动物,go的吉祥物就是这个小动物,它的中文名叫做囊地鼠,它们最大的特点就是挖洞速度特别快,当然可能不止是挖洞啦。

是,TiDB采用go语言编写。TiDB是一个分布式NewSQL数据库;它支持水平弹性扩展、ACID事务、标准SQL、MySQL语法和MySQL协议,具有数据强一致的高可用特性。TiDB架构中的PD储存了集群的元信息,如key在哪个TiKV节点;PD还负责集群的负载均衡以及数据分片等。PD通过内嵌etcd来支持数据分布和容错;PD采用go语言编写。

在写 Go 的过程中经常对比这两种语言的特性,踩了不少坑,也发现了不少有意思的地方,下面本篇就来聊聊 Go 自带的 HttpClient 的超时机制,希望对大家有所帮助。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

SublimeText3 Linux新版
SublimeText3 Linux最新版

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

WebStorm Mac版
好用的JavaScript開發工具

SublimeText3 英文版
推薦:為Win版本,支援程式碼提示!