本文是晚輩對net/http包的一點淺顯的了解,文中如有錯誤的地方請前輩們指出,以免誤導!
轉摘本文也請注明出處:
Go語言備忘錄(3):net/http包的使用模式和源碼解析,多謝!
目錄:
一、http包的3個關鍵類型:
Handler接口:所有請求的處理器、路由ServeMux都滿足該接口;
|
ServeMux結構體:HTTP請求的多路轉接器(路由),它負責将每一個接收到的請求的URL與一個注冊模式的清單進行比對,并調用和URL最比對的模式的處理器。它内部用一個map來儲存所有處理器Handler
- http包有一個包級别變量DefaultServeMux,表示預設路由:var DefaultServeMux = NewServeMux(),使用包級别的http.Handle()、http.HandleFunc()方法注冊處理器時都是注冊到該路由中;
- ServeMux結構體有ServeHTTP()方法(滿足Handler接口),主要用于間接調用它所儲存的處理器的ServeHTTP()方法
http.HandlerFunc函數類型:它滿足Handler接口
|
二、HTTP伺服器的使用模式:
處理函數:隻要函數的簽名為 func(w http.ResponseWriter, r *http.Request) ,均可作為處理函數,即它可以被轉換為http.HandlerFunc函數類型;
模式一:使用預設的路由來注冊處理函數:
+ View Code模式二:使用自定義的路由來注冊處理函數:
模式三:直接自定義一個Server執行個體:該模式可以很友善的管理服務端的行為
|
接下來,我們就跟蹤源碼來仔細的分析下整個執行過程。
三、HTTP伺服器的執行過程:
1.使用http.ListenAndServe()方法啟動服務,它根據給定參數構造Server類型,然後調用server.ListenAndServe()
|
2.而server.ListenAndServe()方法内部調用net.Listen("tcp", addr),該方法内部又調用net.ListenTCP()建立并傳回一個監聽器net.Listener,如下的ln;
|
3.然後把監聽器 ln 斷言轉換為 TCPListener 類型,并根據它構造一個 tcpKeepAliveListener 對象并傳遞給server.Serve()方法;
- 因為TCPListener實作了Listener接口,是以tcpKeepAliveListener也實作了Listener接口,并且它重寫了Accept()方法,目的是為了調用SetKeepAlive(true),讓作業系統為收到的每一個連接配接啟動發送keepalive消息(心跳,為了保持連接配接不斷開)。
|
4.server.Serve()方法調用tcpKeepAliveListener 對象的 Accept() 方法傳回一個連接配接conn(該連接配接啟動了心跳),并為每一個conn建立一個新的go程執行conn.server()方法:具體見代碼中我加的注釋說明
5.而conn.server()方法會讀取請求,然後根據conn内儲存的server來構造一個serverHandler類型,并調用它的ServeHTTP()方法:serverHandler{c.server}.ServeHTTP(w, w.req),該方法的源碼如下:
|
6.如上源碼可以看到,當 handler == nil 時使用預設的DefaultServeMux路由,否則使用在第1步中為Serve指定了的Handler;然後調用該Handler的ServeHTTP方法(該Handler一般被設定為路由ServeMux類型);
7.而路由ServeMux的ServeHTTP方法則會根據目前請求提供的資訊來查找最比對的Handler(這裡為):
|
8.以上查找到的Handler接口值h就是我們事先注冊到路由中與請求比對的Handler;而h的動态類型是HandlerFunc類型(它也滿足Handler接口);
是以,以上 h.ServeHTTP(w, r) 實際上調用的是接口值h中持有的動态值(也就是我們定義的處理函數)
|
至此,整個調用過程講解完畢,至于業務層的處理邏輯,則由各個處理函數實作
四、重定向:
http包自帶了幾個建立常用處理器的函數:FileServer,NotFoundHandler、RedirectHandler、StripPrefix、TimeoutHandler。
而RedirectHandler函數就是用來重定向的:它傳回一個請求處理器,該處理器會對每個請求都使用狀态碼code重定向到網址url
|
好了,本文就暫時講關于http包關于HTTP服務端方面的東西,至于用戶端方面的就簡單引用一下官方文檔說明吧,畢竟用戶端很少用Go實作。
五、用戶端的實作:
Get、Head、Post和PostForm函數發出HTTP/ HTTPS請求。
|
程式在使用完回複後必須關閉回複的主體。
|
要管理HTTP用戶端的頭域、重定向政策和其他設定,建立一個Client:
|
要管理代理、TLS配置、keep-alive、壓縮和其他設定,建立一個Transport:
|
Client和Transport類型都可以安全的被多個go程同時使用。出于效率考慮,應該一次建立、盡量重用。
以上如有誤導的地方,請前輩們務必指出!
讀完覺得學到點什麼,就( 頂一個!)