溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Golang中基于HTTP協議的網絡服務怎么訪問

發布時間:2023-04-13 16:14:41 來源:億速云 閱讀:82 作者:iii 欄目:開發技術

本文小編為大家詳細介紹“Golang中基于HTTP協議的網絡服務怎么訪問”,內容詳細,步驟清晰,細節處理妥當,希望這篇“Golang中基于HTTP協議的網絡服務怎么訪問”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。

    一、HTTP協議的網絡服務

    HTTP協議是基于TCP/IP協議棧的,并且它也是一個面向普通文本的協議。

    只要搞清楚了HTTP請求的報文(報文的頭部(header)和主體(body))應該包含的內容,使用任何一個文本編譯器,就餓可以編寫一個完整的HTTP請求報文。

    在這種情況下,直接使用net.Dial函數,就可以。

    使用net/http代碼包中的程序實體,可以更便捷的訪問基于HTTP協議的網絡服務。其中最便捷的是使用http.Get函數。

    1.1 使用http.Get函數訪問HTTP協議的網絡服務

    package main
    
    import (
    	"fmt"
    	"net/http"
    )
    
    func main() {
    	url1 := "http://www.google.cn/"
    	fmt.Printf("Send request to %q with method GET ... \n", url1)
    	response1, err := http.Get(url1)
    	if err != nil {
    		fmt.Printf("request sending error: %v\n", err)
    	}
    	defer response1.Body.Close()
    	line1 := response1.Proto + " " + response1.Status
    	fmt.Printf("The first line of response: \n %s \n", line1)
    }

    http.Get函數會返回兩個結果值:

    • 第一個結果值的類型是*http.Response,它是網絡服務給我們傳回來的響應內容的結構化表示。

    • 第二個結果值是error類型。它代表了在創建和發送HTTP請求,以及接受和解析HTTP響應的過程中可能發生的錯誤。

    http.Get函數內部會使用缺省的HTTP客戶端,并調用它的Get方法以完成功能。缺省客戶端類型是*http.Client,由公開變量DefaultClient代表。

    1.2 使用缺省客戶端DefaultClient(類型為*http.Client )

    package main
    
    import (
    	"fmt"
    	"net/http"
    )
    
    func main() {
    	url1 := "http://www.google.cn/"
    	fmt.Printf("Send request to %q with method GET ... \n", url1)
    	// response1, err := http.Get(url1)
    	response1, err := http.DefaultClient.Get(url1)
    	if err != nil {
    		fmt.Printf("request sending error: %v\n", err)
    	}
    	defer response1.Body.Close()
    	line1 := response1.Proto + " " + response1.Status
    	fmt.Printf("The first line of response: \n %s \n", line1)
    }

    它的基本類型(http.Client)可以開箱即用。

    1.3 使用http.Client訪問HTTP協議的網絡服務

    package main
    
    import (
    	"fmt"
    	"net/http"
    )
    
    func main() {
    	url1 := "http://www.google.cn/"
    	fmt.Printf("Send request to %q with method GET ... \n", url1)
    	// response1, err := http.Get(url1)
    	// response1, err := http.DefaultClient.Get(url1)
    	var oneClient http.Client
    	response1, err := oneClient.Get(url1)
    	if err != nil {
    		fmt.Printf("request sending error: %v\n", err)
    	}
    	defer response1.Body.Close()
    	line1 := response1.Proto + " " + response1.Status
    	fmt.Printf("The first line of response: \n %s \n", line1)
    }

    http.Client是一個結構體類型,并且它包含的字段是公開的。之所以該類型的零值仍然可以使用,是因為它的這些字段要么存在著響應的缺省值,要么其零值直接可以使用,且代表著特定的含義。

    二、http.Client中的Transport字段

    http.Client類型中的Transport字段代表著:向網絡服務發送HTTP請求,并從網絡服務接收HTTP響應的操作過程。

    Transport字段的RoundTrip方法實現單次HTTP事務(或者說基于HTTP協議的單詞交互)需要的所有步驟。

     Transport 字段是http.RoundTrip接口類型,它有一個缺省值,這個缺省值的變量名為DefaultTransport。DefaultTransport的實際類型為*http.Transport,*http.Transport可以被復用,并且是線程安全的。

    如果沒有顯式的為http.Client中的Transport字段賦值,這個Client就會直接使DefaultTransport。

     http.Client中的Timeout字段,代表前面所說的單詞HTTP事務的超時時間,它time.Duration類型,它的零值是可用的,用于表示沒有設置超時時間。

    (1)http.Transport類型中的DialContext字段

    http.Transport類型,在內部使用一個net.Dialer類型的值,并且會把該值的Timeout字段的值,設定為30秒。

    也就是說,這個Dialer值如果在30秒內還沒有建立好網絡連接,那么就會被判定為操作超時。

    在DefaultTransport的值被初始化的時候,這樣的Dialer值的DialContext方法會被賦給前者DialContext字段:

    var DefaultTransport RoundTripper = &Transport{
    	Proxy: ProxyFromEnvironment,
    	DialContext: defaultTransportDialContext(&net.Dialer{
    		Timeout:   30 * time.Second,
    		KeepAlive: 30 * time.Second,
    	}),
    	ForceAttemptHTTP2:     true,
    	MaxIdleConns:          100,
    	IdleConnTimeout:       90 * time.Second,
    	TLSHandshakeTimeout:   10 * time.Second,
    	ExpectContinueTimeout: 1 * time.Second,
    }
    
    func defaultTransportDialContext(dialer *net.Dialer) func(context.Context, string, string) (net.Conn, error) {
    	return dialer.DialContext
    }

    KeepAlive的背后是一種針對網絡連接(更確切地說,是TCP連接)的存活探測機制。它的值用于表示每隔多長時間發送一次探測包。當該值不大于0時,則表示不開啟這種機制。

    DefaultTransport會把這個字段的值設定為30秒。

    (2)http.Transport類型中的其它字段

    一些是關于超時操作

    • IdleConnTimeout:含義是空閑的連接在多久之后就應該關閉。

     DefaultTransport 會把該字段的值設定為90秒。

    如果該值為0,那么就表示不關閉空閑連接。注意,這樣可能會造成資源的泄露。

    • ResponseHeaderTimeout:含義是,從客戶端把請求完全遞交給操作系統到從操作系統那里接收到響應報文頭到最長時長。

     DefaultTransport并沒有設定該字段的值。

    •  ExpectContinueTimeout:含義是,在客戶端提交了請求報文頭之后,等待接收第一個響應報文頭的最長時間。

     DefaultTransport 把該字段的值設定為1秒。

    在客戶端想要使用HTTP的“POST”方法把一個很大的報文體發送給服務端的時候,它可以先通過發送一個包含了“Expect: 100-continue”的請求報文頭,來詢問服務端是否愿意接受這個大報文體。這個字段就是用于設定在這種情況下的超時時間的。

    注意,如果該字段的值不大于0,那么無論多大的請求報文體都將會被立即發送出去。

    TLSHandshakeTimeout:TLS是Transport Layer Security 的縮寫,可以被翻譯為傳輸層安全。這個字段代表了基于TLS協議的連接在被建立時的握手階段的超時時間。

    DefaultTransport 把該字段的值設置為10秒。

    若該值為0,則表示對這個值不設限。

    一些與IdleConnTimeout相關的字段值

    • MaxIdleConns:用于控制訪問所有主機的最大空閑連接。如果為0,不做限制。

    DefaultTransport 把MaxIdleConns設定為100。

    MaxIdleConns字段只會對空閑連接的總數做出限定。

    • MaxIdleConnsPerHost: 控制Transport值訪問每一個網絡服務的最大空閑連接數。如果為0,將使用缺省值2, 這個缺省值由DefaultMaxIdleConnsPerHost所代表。

    也就是說,默認情況下,對于某一個Transport值訪問的每一個網絡服務,它的空閑連接數都最多只能由兩個。

    • MaxConnsPerHost:針對某一個Transport值訪問的每一個網絡服務的最大連接數,不論這些連接是否是空閑的。

    該字段沒有缺省值,零值表示不限定。

    MaxIdleConns和MaxIdleConnsPerHost兩個與空閑連接數有關的字段的值應該是聯動的,所以,有時需要根據實際情況定制它們,可以參考DefaultTransport變量的聲明。

    三、為什么會出現空閑的連接

    3.1 空閑連接的產生

    HTTP協議有一個請求報文頭,叫做“Connection”。在HTTP協議的1.1 版本中,這個報文頭的值默認是“keep-alive”。

    在這種情況下,網絡連接都是持久連接,它們會在當前的HTTP事務完成后仍然保持著連通性,因此是可以被復用的。

    連接的可復用,帶來兩種可能:

    • 一種可能是,針對同一個網絡服務,有新的HTTP請求被提交,該連接被再次使用。

    • 另一種可能是,不再有對該網絡服務的HTTP請求,該連接被閑置。(產生空閑的連接)

    后一種情況就產生了空閑連接。另外,如果分配給某一個網絡服務的連接過多的話,也可能會導致空閑連接的產生。因為每一個新遞交的HTTP請求,都只會征用一個空閑的連接。所以,為空閑連接設定限制,在大多數情況下都是很有必要的,也是需要斟酌的。

    3.2 杜絕空閑連接的產生

    如果想徹底杜絕空閑連接的產生,那么可以在初始化的時候,把它的DisableKeepAlives字段的值設定為true。這時,HTTP請求的“Connection”報文頭的值就會被設置為“close”。這會告訴網絡服務,這個網絡連接不必保持,當前的HTTP事務完成后就可以斷開它。

    如此一來,每當一個HTTP請求被遞交時,就會產生一個新的網絡連接。這樣做會明顯地加重網絡服務以及客戶端的負載。所以,在一般情況下,我們都不要去設置這個DisableKeepAlive字段。

    在net.Dialer類型中,也有一個看起來很相似的字段KeepAlive。不過,它與前面所說的HTTP 持久連接不是一個概念,KeepAlive是直接作用在底層的socket上的。

    KeepAlive的背后是一種針對網絡連接(更確切地說,是TCP連接)的存活探測機制。它的值用于表示每隔多長時間發送一次探測包。當該值不大于0時,則表示不開啟這種機制。DefaultTransport會把這個字段的值設定為30秒。

    四、http.Server

    http.Server類型與http.Client相對應。http.Server代表的是基于HTTP協議的服務端,或者網絡服務。

    4.1 http.Server類型的ListenAndServe方法

    http.Server類型的ListenAndServe方法的功能是:監聽一個基于TCP協議的網絡地址,并對接收到的HTTP請求進行處理。

    • 這個方法默認會開啟針對網絡連接的存活探測機制,以保證連接是持久的。

    • 同時,該方法會一直執行,直到有嚴重的錯誤發生或被外界關掉。

    當被外界關掉時,它會返回一個由http.ErrServerClosed變量代表的錯誤值。

    4.2 ListenAndServe方法主要做的事情

    func (srv *Server) ListenAndServe() error {
    	if srv.shuttingDown() {
    		return ErrServerClosed
    	}
    	addr := srv.Addr
    	if addr == "" {
    		addr = ":http"
    	}
    	ln, err := net.Listen("tcp", addr)
    	if err != nil {
    		return err
    	}
    	return srv.Serve(ln)
    }

    ListenAndServe方法主要會做下面的事情:

    • 檢查當前的http.Server類型的值的Addr字段。

    該字段的值代表了當前的網絡服務需要使用的網絡地址。即:IP地址和端口號。如果這個字段的值為空字符串,那么就用":http"代替。

    也就是說,使用任何可以代表本機的域名和IP地址,并且端口號為80.

    • 通過調用net.Listen函數在已確定的網絡地址上啟動基于TCP協議的監聽。

    • 檢查net.Listen 函數返回的錯誤值。

    如果該錯誤值不為nil,那么就直接返回該值。否則,通過調用當前值的Serve方法準備接受和處理將要到來的HTTP請求。

    4.3 (衍生問題)net.Listen 函數都做了哪些事情

    net.Listen函數做的事情:

    • 解析參數值中包含的網絡地址隱含的IP地址和端口號;

    • 根據給定的網絡協議,確定監聽的方法,并開始進行監聽;

    這里還可以延伸到net.socket函數,以及socket相關的知識。

    4.4 (衍生問題)http.Server類型的Serve方法是怎么接受和處理HTTP請求的

    在一個for循環中,網絡監聽的Accept方法會被不斷的調用,

    	for {
    		rw, err := l.Accept()
      }

    該方法會返回兩個結果值:

    • 第一個結果值是net.Conn 類型,代表包含了新到來的HTTP請求的網絡連接;

    • 第二個結果值是error類型值,代表可能發生的錯誤。

    如果錯誤不為nil,除非它代表了一個暫時性的錯誤,否則循環都會被終止。如果是暫時性的錯誤,那么循環的下一次迭代將會在一段時間之后開始執行。

    如果這里的Accept方法沒有返回非nil的錯誤值,那么這里的程序將會把它的第一個結果值包裝成一個*http.conn類型的值,然后通過在新的goroutine中調用這個*http.conn 類型值的serve方法,來對當前的HTTP請求進行處理。

    HTTP請求相關的,更多的衍生問題:

    • 這個*http.conn類型值的狀態有幾種,分別代表著處理的哪個階段?

    • 處理的過程中會用到哪些讀取器和寫入器,它們的作用分別是什么?

    • 這里的程序是怎么調用我們自定義的處理函數的?

    五、思考:怎么優雅地停止基于HTTP協議的網絡服務程序?

    srv.Shutdown(context.Background()) 的方式停止服務,通過RegisterOnShutdown可添加服務停止時的調用。

    讀到這里,這篇“Golang中基于HTTP協議的網絡服務怎么訪問”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女