1. Golang-web工作機制
1.web工作方式:
瀏覽器URL –> 請求DNS伺服器 ->解析網域名稱到對應的IP –> 建立TCP協議 –>發送Http Request –>Web伺服器處理請求 –>Http Response返回用戶端 –>渲染響應體 –>呈現給使用者UI介面
2.Http請求
GET請求: http://xx.xx.com?name=test1&id=123 //用?分隔URL和傳輸資料,參數之間用&串連 URL有長度限制、明文傳輸,參數在URL中。
3.http響應
狀態代碼:1XX:請求被接收,繼續處理 2XX:成功,請求已經被成功處理 3XX:重新導向 4XX:用戶端錯誤 5XX:伺服器端錯誤
4.http包啟動並執行流程:
(1.)建立Listen Socket 監聽指定連接埠,等待用戶端的請求到來。
(2.)ListenSocket 接收用戶端的請求,得到Client Socket,通過Client Socket與用戶端通訊。
(3.)處理用戶端的請求,首先從Client Socket讀取Http請求的協議頭,如果是post請求,還需要讀取用戶端提交的資料,然後交給相應的handler處理請求,handler處理完後,將資料返回給用戶端。
(4.)具體實現:
初始化一個server, 調用 net.Listen(“tcp”,addr) 監控連接埠 ,srv.Serve(net.Listener)接收用戶端的請求資訊。建立串連,執行gorouting
(5.) Go http的兩個核心功能,conn和ServMux,實現高並發和高效能。
srv.netConn(rw) //每次請求都會建立一個串連,這個連結中儲存了這次請求的資訊,並將該資訊傳遞給對應的handler,handler讀取響應的header資訊。這樣就保持了每個請求的獨立性。
go c.serve()
type ServeMux struct {
mu sync.RWMutex //鎖,由於請求設計到並發處理,因此需要加鎖
m map[string]muxEnty //路由規則,一個string(路由運算式)對應一個Mux實體{ explicit bool //是否精確匹配 h Handler //這個路由運算式對應哪個handler pattern string //匹配字串}
hosts bool //是否在任意的規則中帶有host資訊
}
type Handler interface {
ServeHTTP(RespnseWriter,*Request) //路由實現器
}
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
if r.RequestURI == "*" {
w.Header().Set("Connection", "close")
w.WriteHeader(StatusBadRequest)
return
}
h, _ := mux.Handler(r)
h.ServeHTTP(w, r)
}
func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) {
if r.Method != "CONNECT" {
if p := cleanPath(r.URL.Path); p != r.URL.Path {
_, pattern = mux.handler(r.Host, p)
return RedirectHandler(p, StatusMovedPermanently), pattern
}
}
return mux.handler(r.Host, r.URL.Path)
}
func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) {
mux.mu.RLock()
defer mux.mu.RUnlock()
// Host-specific pattern takes precedence over generic ones
if mux.hosts {
h, pattern = mux.match(host + path)
}
if h == nil {
h, pattern = mux.match(path)
}
if h == nil {
h, pattern = NotFoundHandler(), ""
}
return
}
5.執行流程:
首先調用Http.HandleFunc
按順序做了幾件事:
1 調用了DefaultServeMux的HandleFunc
2 調用了DefaultServeMux的Handle
3 往DefaultServeMux的map[string]muxEntry中增加對應的handler和路由規則
其次調用http.ListenAndServe(":9090", nil)
按順序做了幾件事情:
1 執行個體化Server
2 調用Server的ListenAndServe()
3 調用net.Listen("tcp", addr)監聽連接埠
4 啟動一個for迴圈,在迴圈體中Accept請求
5 對每個請求執行個體化一個Conn,並且開啟一個goroutine為這個請求進行服務go c.serve()
6 讀取每個請求的內容w, err := c.readRequest()
7 判斷handler是否為空白,如果沒有設定handler(這個例子就沒有設定handler),handler就設定為DefaultServeMux
8 調用handler的ServeHttp
9 在這個例子中,下面就進入到DefaultServeMux.ServeHttp
10 根據request選擇handler,並且進入到這個handler的ServeHTTP
mux.handler(r).ServeHTTP(w, r)
11 選擇handler:
A 判斷是否有路由能滿足這個request(迴圈遍曆ServerMux的muxEntry)
B 如果有路由滿足,調用這個路由handler的ServeHttp
C 如果沒有路由滿足,調用NotFoundHandler的ServeHttp