golang自定义路由控制实现(一)
????由于本人之前一直是Java Coder,在Java web開發中其實大家都很依賴框架,所以當在學習Golang的時候,自己便想著在Go開發中脫離框架,自己動手造框架來練習。通過學習借鑒Java的思想還有部分框架的源碼,在golang上面進行實現,從而達到對Java和Golang的同時學習目的,這就很美滋滋了。
????Golang中http的設計非常輕量,又兼具很高的擴展性,初學者都可以輕易的設計出自定義的路由功能,使用上十分簡單(這里……來吐槽一下Java的Servlet,雖然我也對Java愛得深沉),下面請看Go的Demo。
????短短的幾行代碼便可以成功注冊一個接口并跑起服務。但是原生的開發方式提供的功能是比較精簡的目前幾乎所有的Web應用路由實現都是基于http默認的路由器,但是Go自帶的路由器有幾個限制:
- 不支持參數設定,例如/user/:uid 這種泛類型匹配。
- 無法很好的支持REST模式,無法限制訪問的方法,例如上面的例子中,用戶訪問/foo,可以用GET、POST、DELETE、HEAD等方式訪問。
- 一般網站的路由規則太多了,編寫繁瑣,可以通過struct的方法進行一種簡化。
????Go有如此限制跟http提供的默認方式有關,我們先看下http兩個關鍵的struct
????我們需要重點關鍵兩個地方,一個是ServeMux 中的參數m,它的類型是 map[string]muxEntry ,這里我們自然而然可以想到,參數m負責路由分發。第二個重點則是muxEntry,muxEntry的h Handler 對應的就是我們編寫的接口,而圍繞這個接口,http并沒有其他過多的功能,甚至連像Java中制定一套統一web開發標準都沒有。因此http中只是提供最基礎的功能,用戶則需要以這些功能為基礎,進而YY出自己想要的框架或者更豐富的功能。
????首先我們問題,能夠快速簡單的設置Http Method,以方便日后支持RESTFUL的URL規范。有兩種簡單的做法,第一種做法是使用二維Map ,即map[string]map[string]http.HandlerFunc,其中一維的鍵String表示請求method比如post, get 等。二維的鍵string表示要匹配的URL地址, http.HandlerFunc當然就是處理URL請求的具體方法。第二種做法即是筆者采用的做法,其實是第一種做法演變而來的,HTTP 中Method的種類是固定的,其實我們完全可以用一個數組,而值為map[string]http.HandlerFunc來實現。
????看完上面常量的設置,想必讀者已經知道了我的意思,e.g:array[0]表示GET方法下所有的接口的集合,array[1]表示POST方法下所有的接口的集合基本原理其實也簡單,把Get方法下的所有的接口都存儲到array[0]的值中,以此推理其他方法。原理簡單,但是一個框架的設計必須高內聚低耦合,一個Web框架中路由分發是基礎,在該此處上需要建立更多的功能,比如說過濾器等。在初期設計的時候必須保證要有可擴展性,所以筆者認為難點在于此。下面直接上代碼,對應的代碼有充分的注釋。
package odserverimport ("net/http" ) //實現IOdServer的接口,以及http提供ServeHttp方法 type OdServer struct {router MethodMaps }type IOdServer interface {GET(url string, f HandlerFunc)POST(url string, f HandlerFunc)PUT(url string, f HandlerFunc)DELETE(url string, f HandlerFunc) }type HandlerMapped struct {f HandlerFunc } //接口函數單位,即我們編寫代碼邏輯的函數 type HandlerFunc func(w http.ResponseWriter, req *http.Request)func Default() *OdServer {return &OdServer{router:NewRouter(),} }//實現Handler接口,匹配方法以及路徑 func (o *OdServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {//轉發給doHandler進行執行o.doHandler(w,req) } //判斷需要執行的Http Method,從而查找對應的接口并且執行 func (o *OdServer) doHandler(w http.ResponseWriter, req *http.Request) {switch req.Method {case http.MethodGet:{if hm, ok := o.router.GetMapping(req.URL.RequestURI()); ok {hm.f(w, req)}}case http.MethodPost:{if hm, ok := o.router.PostMapping(req.URL.RequestURI()); ok {hm.f(w, req)}}case http.MethodDelete:{if hm, ok := o.router.DeleteMapping(req.URL.String()); ok {hm.f(w, req)}}case http.MethodPut:{if hm, ok := o.router.PutMapping(req.URL.String()); ok {hm.f(w, req)}}default:{}} }func (o *OdServer) GET(url string, f HandlerFunc) {o.router.GetAdd(url, HandlerMapped{f: f}) } func (o *OdServer) POST(url string, f HandlerFunc) {o.router.PostAdd(url, HandlerMapped{f: f}) } func (o *OdServer) PUT(url string, f HandlerFunc) {o.router.PutAdd(url, HandlerMapped{f: f}) } func (o *OdServer) DELETE(url string, f HandlerFunc) {o.router.DeleteAdd(url, HandlerMapped{f: f}) } package odserver/** 提供基本的路由功能,添加路由,查找路由*/ const (GET = iotaPOSTPUTDELETECONNECTIBNGHEADOPTIONSPATCHTRACE )func NewRouter() MethodMaps {return []handler{GET: make(handler),POST: make(handler),PUT: make(handler),DELETE: make(handler),} }type MethodMaps [] handler type handler map[string]HandlerMapped //映射路由,獲取Get方法下對應的接口 func (m MethodMaps) GetMapping(url string) (HandlerMapped, bool) {if hm, ok := m[GET][url]; ok {return hm, true}return HandlerMapped{}, false } //映射路由,獲取Post方法下對應的接口 func (m MethodMaps) PostMapping(url string) (HandlerMapped, bool) {if hm, ok := m[POST][url]; ok {return hm, true}return HandlerMapped{}, false } //映射路由,獲取Delete方法下對應的接口 func (m MethodMaps) DeleteMapping(url string) (HandlerMapped, bool) {if hm, ok := m[DELETE][url]; ok {return hm, true}return HandlerMapped{}, false } //映射路由,獲取Put方法下對應的接口 func (m MethodMaps) PutMapping(url string) (HandlerMapped, bool) {if hm, ok := m[PUT][url]; ok {return hm, true}return HandlerMapped{}, false } //增加Get方法下的接口 func (m MethodMaps) GetAdd(url string, mapped HandlerMapped) {if _, ok := m.GetMapping(url); ok {panic("duplicate url with get method")}m[GET].SetUrl(url,mapped) } //增加Post方法下的接口 func (m MethodMaps) PostAdd(url string, mapped HandlerMapped) {if _, ok := m.GetMapping(url); ok {panic("duplicate url with Post method")}m[POST].SetUrl(url,mapped)} //增加Put方法下的接口 func (m MethodMaps) PutAdd(url string, mapped HandlerMapped) {if _, ok := m.GetMapping(url); ok {panic("duplicate url with Put method")}m[PUT].SetUrl(url,mapped)} //增加Delete方法下的接口 func (m MethodMaps) DeleteAdd(url string, mapped HandlerMapped) {if _, ok := m.GetMapping(url); ok {panic("duplicate url with Delete method")}m[DELETE].SetUrl(url,mapped) } func (h handler) SetUrl(url string, mapped HandlerMapped) {h[url] = mapped }????如我所說,我覺得學習Golang比較有意思的是,可以將從Java里學到的東西,轉之在Golang里嘗試實現,不僅學習了Golang,還使得自己對Java的認識進一步提升。如果讀者有更好的方法,不吝賜教
參考資料:# Golang學習筆記 - 標準庫"net/http"的簡析及自制簡單路由框架
總結
以上是生活随笔為你收集整理的golang自定义路由控制实现(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VNCTF2025_Crypto
- 下一篇: helm部署redis集群