先來(lái)一個(gè)例子吧:
程序運(yùn)行起來(lái)狈谊,在Postman分別發(fā)送get(http://127.0.0.1:8888/sayHelloWorld?name=我是get請(qǐng)求)搂漠、post(http://127.0.0.1:8888/sayHelloWorld,name:我是post請(qǐng)求)請(qǐng)求:
一、Web工作方式的幾個(gè)概念:
1.Request:用戶請(qǐng)求的信息,用來(lái)解析用戶的請(qǐng)求信息撵幽,包括post、get礁击、cookie盐杂、url等信息。
2.Response:服務(wù)器需要反饋給客戶端的信息哆窿。
3.Conn:用戶的每次請(qǐng)求鏈接链烈。
4Handler:處理請(qǐng)求和生產(chǎn)返回信息的處理邏輯。
5.ResponseWriter: 生成Response的接口挚躯。
6.ServeMux: 路由强衡,ServeMux也是一種Handler
二、http包執(zhí)行流程
1.創(chuàng)建Listen Socket 監(jiān)聽(tīng)指定的端口秧均,等待客戶端請(qǐng)求到來(lái)食侮。
2.Listen Socket接受客戶端的請(qǐng)求号涯,得到Client Socket目胡,接下來(lái)通過(guò)Client Socket與客戶端通信。
3.處理客戶端的請(qǐng)求链快,首先從Client Socket 讀取HTTP請(qǐng)求的協(xié)議頭誉己,如果是POST方法,還可以讀取客戶端提交的數(shù) ? ? ? ? ?據(jù)域蜗,然后交給相應(yīng)的handler處理請(qǐng)求巨双,handle處理完畢準(zhǔn)備好客戶端需要的數(shù)據(jù),通過(guò)Client Socket寫(xiě)給客戶端霉祸。
三筑累、Go代碼執(zhí)行流程(結(jié)合原碼來(lái)看更容易理解)
1、首先調(diào)用http.HandleFunc("/",HandleRequest)
a. 調(diào)用了DefaultServerMux的HandleFunc
b.調(diào)用了DefaultServerMux的Handle
c.往DefaultServeMux的map[string]muxEntry中增加對(duì)應(yīng)的handler和路由規(guī)則
2丝蹭、其次調(diào)用http.ListenAndServe(":8888",nil)
a. 實(shí)例化Serverserver := &Server{Addr: addr, Handler: handler}
b. 調(diào)用了Server.ListenAndServe()
c. 調(diào)用了net.Listen("tcp", addr) 監(jiān)聽(tīng)端口慢宗,底層用TCP協(xié)議搭建了一個(gè)服務(wù),然后監(jiān)聽(tīng)我們?cè)O(shè)置的端口
d. 啟動(dòng)一個(gè)for循環(huán),在循環(huán)體中接受請(qǐng)求
e.對(duì)每個(gè)請(qǐng)求實(shí)例化一個(gè)Conn ?c := srv.newConn(rw)并且開(kāi)啟一個(gè)goroutine為這個(gè)請(qǐng)求進(jìn)行服務(wù)
? ?go c.serve(ctx)
f. 讀取每個(gè)請(qǐng)求的內(nèi)容w, err := c.readRequest(ctx)
g. 判斷handler是否為空镜沽,如果沒(méi)有設(shè)置handler敏晤,handler就設(shè)置為DefaultServeMux
h. ?根據(jù)request選擇handler 并且進(jìn)入到這個(gè)handler的ServeHttp mux.handler(r).ServeHTTP(w, r)
i. 選擇路由:
1)判斷有沒(méi)有路由滿足這個(gè)request(循環(huán)遍歷ServerMux的muxEntry)
2)如果有路由滿足,調(diào)用這個(gè)路由handler的serveHttp
3)如果沒(méi)有路由滿足缅茉,調(diào)用NotFoundHandler的ServeHttp