摘要:中的設(shè)計(jì)非常輕量,又兼具很高的擴(kuò)展性,初學(xué)者都可以輕易的設(shè)計(jì)出自定義的路由功能,使用上十分簡單這里來吐槽一下的,雖然我也對愛得深沉,下面請看的。一般網(wǎng)站的路由規(guī)則太多了,編寫繁瑣,可以通過的方法進(jìn)行一種簡化。
????由于本人之前一直是Java Coder,在Java web開發(fā)中其實(shí)大家都很依賴框架,所以當(dāng)在學(xué)習(xí)Golang的時(shí)候,自己便想著在Go開發(fā)中脫離框架,自己動(dòng)手造框架來練習(xí)。通過學(xué)習(xí)借鑒Java的思想還有部分框架的源碼,在golang上面進(jìn)行實(shí)現(xiàn),從而達(dá)到對Java和Golang的同時(shí)學(xué)習(xí)目的,這就很美滋滋了。 ????Golang中http的設(shè)計(jì)非常輕量,又兼具很高的擴(kuò)展性,初學(xué)者都可以輕易的設(shè)計(jì)出自定義的路由功能,使用上十分簡單(這里……來吐槽一下Java的Servlet,雖然我也對Java愛得深沉),下面請看Go的Demo。
func HelloServer1(w http.ResponseWriter, req *http.Request) {
fmt.Fprint(w,"hello world")
}
func main() {
http.HandleFunc("/test", HelloServer1)
err := http.ListenAndServe(":8080", nil)
if err != nil {
log.Fatal("ListenAndServe: ", err.Error())
}
}
????短短的幾行代碼便可以成功注冊一個(gè)接口并跑起服務(wù)。但是原生的開發(fā)方式提供的功能是比較精簡的目前幾乎所有的Web應(yīng)用路由實(shí)現(xiàn)都是基于http默認(rèn)的路由器,但是Go自帶的路由器有幾個(gè)限制:
不支持參數(shù)設(shè)定,例如/user/:uid 這種泛類型匹配。
無法很好的支持REST模式,無法限制訪問的方法,例如上面的例子中,用戶訪問/foo,可以用GET、POST、DELETE、HEAD等方式訪問。
一般網(wǎng)站的路由規(guī)則太多了,編寫繁瑣,可以通過struct的方法進(jìn)行一種簡化。 ????Go有如此限制跟http提供的默認(rèn)方式有關(guān),我們先看下http兩個(gè)關(guān)鍵的struct
type ServeMux struct {
mu sync.RWMutex
m map[string]muxEntry
hosts bool // whether any patterns contain hostnames
}
type muxEntry struct {
explicit bool
h Handler
pattern string
}
????我們需要重點(diǎn)關(guān)鍵兩個(gè)地方,一個(gè)是ServeMux 中的參數(shù)m,它的類型是 map[string]muxEntry ,這里我們自然而然可以想到,參數(shù)m負(fù)責(zé)路由分發(fā)。第二個(gè)重點(diǎn)則是muxEntry,muxEntry的h Handler 對應(yīng)的就是我們編寫的接口,而圍繞這個(gè)接口,http并沒有其他過多的功能,甚至連像Java中制定一套統(tǒng)一web開發(fā)標(biāo)準(zhǔn)都沒有。因此http中只是提供最基礎(chǔ)的功能,用戶則需要以這些功能為基礎(chǔ),進(jìn)而YY出自己想要的框架或者更豐富的功能。 ????首先我們問題,能夠快速簡單的設(shè)置Http Method,以方便日后支持RESTFUL的URL規(guī)范。有兩種簡單的做法,第一種做法是使用二維Map ,即map[string]map[string]http.HandlerFunc,其中一維的鍵String表示請求method比如post, get 等。二維的鍵string表示要匹配的URL地址, http.HandlerFunc當(dāng)然就是處理URL請求的具體方法。第二種做法即是筆者采用的做法,其實(shí)是第一種做法演變而來的,HTTP 中Method的種類是固定的,其實(shí)我們完全可以用一個(gè)數(shù)組,而值為map[string]http.HandlerFunc來實(shí)現(xiàn)。
const ( GET = iota POST PUT DELETE CONNECTIBNG HEAD OPTIONS PATCH TRACE )
????看完上面常量的設(shè)置,想必讀者已經(jīng)知道了我的意思,e.g:array[0]表示GET方法下所有的接口的集合,array[1]表示POST方法下所有的接口的集合基本原理其實(shí)也簡單,把Get方法下的所有的接口都存儲(chǔ)到array[0]的值中,以此推理其他方法。原理簡單,但是一個(gè)框架的設(shè)計(jì)必須高內(nèi)聚低耦合,一個(gè)Web框架中路由分發(fā)是基礎(chǔ),在該此處上需要建立更多的功能,比如說過濾器等。在初期設(shè)計(jì)的時(shí)候必須保證要有可擴(kuò)展性,所以筆者認(rèn)為難點(diǎn)在于此。下面直接上代碼,對應(yīng)的代碼有充分的注釋。
/**
odserver.go
*/
package odserver
import (
"net/http"
)
//實(shí)現(xiàn)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
}
//接口函數(shù)單位,即我們編寫代碼邏輯的函數(shù)
type HandlerFunc func(w http.ResponseWriter, req *http.Request)
func Default() *OdServer {
return &OdServer{
router:NewRouter(),
}
}
//實(shí)現(xiàn)Handler接口,匹配方法以及路徑
func (o *OdServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
//轉(zhuǎn)發(fā)給doHandler進(jìn)行執(zhí)行
o.doHandler(w,req)
}
//判斷需要執(zhí)行的Http Method,從而查找對應(yīng)的接口并且執(zhí)行
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})
}
/**
router.go
*/
package odserver
/**
提供基本的路由功能,添加路由,查找路由
*/
const (
GET = iota
POST
PUT
DELETE
CONNECTIBNG
HEAD
OPTIONS
PATCH
TRACE
)
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方法下對應(yīng)的接口
func (m MethodMaps) GetMapping(url string) (HandlerMapped, bool) {
if hm, ok := m[GET][url]; ok {
return hm, true
}
return HandlerMapped{}, false
}
//映射路由,獲取Post方法下對應(yīng)的接口
func (m MethodMaps) PostMapping(url string) (HandlerMapped, bool) {
if hm, ok := m[POST][url]; ok {
return hm, true
}
return HandlerMapped{}, false
}
//映射路由,獲取Delete方法下對應(yīng)的接口
func (m MethodMaps) DeleteMapping(url string) (HandlerMapped, bool) {
if hm, ok := m[DELETE][url]; ok {
return hm, true
}
return HandlerMapped{}, false
}
//映射路由,獲取Put方法下對應(yīng)的接口
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
}
????如我所說,我覺得學(xué)習(xí)Golang比較有意思的是,可以將從Java里學(xué)到的東西,轉(zhuǎn)之在Golang里嘗試實(shí)現(xiàn),不僅學(xué)習(xí)了Golang,還使得自己對Java的認(rèn)識(shí)進(jìn)一步提升。如果讀者有更好的方法,不吝賜教 參考資料:# Golang學(xué)習(xí)筆記 - 標(biāo)準(zhǔn)庫"net/http"的簡析及自制簡單路由框架
? 作者:plz叫我紅領(lǐng)巾
? 出處:juejin.im/post/5ce244…
本博客歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/7172.html
摘要:中的設(shè)計(jì)非常輕量,又兼具很高的擴(kuò)展性,初學(xué)者都可以輕易的設(shè)計(jì)出自定義的路由功能,使用上十分簡單這里來吐槽一下的,雖然我也對愛得深沉,下面請看的。一般網(wǎng)站的路由規(guī)則太多了,編寫繁瑣,可以通過的方法進(jìn)行一種簡化。????由于本人之前一直是Java Coder,在Java web開發(fā)中其實(shí)大家都很依賴框架,所以當(dāng)在學(xué)習(xí)Golang的時(shí)候,自己便想著在Go開發(fā)中脫離框架,自己動(dòng)手造框架來練習(xí)。通過學(xué)...
摘要:,托管于騰訊云容器平臺(tái)容器編排工具。適配我們目前的服務(wù)部署在騰訊云托管,節(jié)點(diǎn)使用核的網(wǎng)絡(luò)增強(qiáng)型機(jī)器,所有的后端服務(wù)都以部署,集群外部署高可用支持集群內(nèi)服務(wù)發(fā)現(xiàn),數(shù)據(jù)庫以為主,消息隊(duì)列采用。 距離2017年的見聞技術(shù)架構(gòu)調(diào)整接近2年,隨著業(yè)務(wù)線的發(fā)展,見聞技術(shù)部的項(xiàng)目數(shù)量、項(xiàng)目架構(gòu)類型、基礎(chǔ)設(shè)施規(guī)模、服務(wù)變更頻率都在不斷地增長,帶給SRE的挑戰(zhàn)是如何能更快地助力于開發(fā)人員更快更穩(wěn)定地部署...
摘要:相關(guān)原理概述先來講講什么是容器網(wǎng)絡(luò)接口是一種操作容器網(wǎng)絡(luò)規(guī)范,包含方法規(guī)范,參數(shù)規(guī)范等。只關(guān)心容器的網(wǎng)絡(luò)連接,在容器創(chuàng)建時(shí)分配網(wǎng)絡(luò)資源,并在刪除容器時(shí)刪除分配的資源。容器創(chuàng)建成功后具有一個(gè)網(wǎng)絡(luò)空間,此時(shí)調(diào)用插件方法進(jìn)行網(wǎng)絡(luò)設(shè)置。 相關(guān)原理概述 先來講講什么是CNI? CNI(容器網(wǎng)絡(luò)接口)是一種操作容器網(wǎng)絡(luò)規(guī)范,包含方法規(guī)范,參數(shù)規(guī)范等。CNI只關(guān)心容器的網(wǎng)絡(luò)連接,在容器創(chuàng)建時(shí)分配網(wǎng)絡(luò)...
閱讀 740·2023-04-25 19:43
閱讀 3986·2021-11-30 14:52
閱讀 3816·2021-11-30 14:52
閱讀 3873·2021-11-29 11:00
閱讀 3808·2021-11-29 11:00
閱讀 3907·2021-11-29 11:00
閱讀 3584·2021-11-29 11:00
閱讀 6197·2021-11-29 11:00