亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Golang中間件設(shè)計示例詳解

 更新時間:2023年05月10日 09:26:42   作者:未來誰可知  
這篇文章主要介紹了Golang中間件設(shè)計示例,中間件是在HTTP請求處理過程中,對請求進行處理的一種模式,中間件可以在請求到達處理器之前或之后對請求進行攔截,修改或者增強,同時可以對響應(yīng)進行處理,需要的朋友可以參考下

什么是中間件

中間件:將這些非業(yè)務(wù)邏輯代碼抽象出來,封裝好,提供接口給控制器使用

裝飾器模式:將最核心的代碼一層層裝飾,返回的時候一層層出來

動手設(shè)計中間件

首先我們從之前的Controller開始,之前寫了一個可以超時的controller但是那是寫在了代碼里,我們能不能變成中間件為我們自動去判斷超時呢!

首先在framework/timeout.go寫下我們的中間件方法:

// 包裝所有注冊的Controller 然后前置方法加上錯誤panic和超時控制
func TimeOutController(fun ControllerHandler, d time.Duration) ControllerHandler {
   return func(c *Context) error {
      finish := make(chan struct{}, 1)
      panicChan := make(chan interface{}, 1)
      context, cancel := context.WithTimeout(c, d)
      defer cancel()
      c.Request.WithContext(context)
      go func() {
         defer func() {
            if p := recover(); p != nil {
               panicChan <- p
            }
         }()
         fun(c)
         finish <- struct{}{}
      }()
      select {
      case p := <-panicChan:
         log.Println(p)
         c.ResponseWriter.WriteHeader(500)
      case <-finish:
         log.Println("finish")
      case <-context.Done():
         c.SetHasTimeOut()
         c.ResponseWriter.Write([]byte("time out"))
      }
      return nil
   }
}

但是這樣的調(diào)用的話就變成了

core.Get("/user/login", framework.TimeOutController(UserLoginController,time.Second*2))

如果有新的中間件要包裹,那豈不是顯示寫出來會很長,一層一層的!而且這個實現(xiàn),也只能為一個controller需要的時候去包裹一下,只是省了寫多個超時的代碼,但還是要自己顯示的調(diào)用!

使用流水線模式

當不要嵌套之后,那我們就用一個數(shù)組將這些中間件都存起來然后順序自己執(zhí)行,這樣既不用調(diào)用,也不用擔心嵌套了

需要處理的地方:

  • 第一個是在此次請求處理的入口處,即 Core 的 ServeHttp;
  • 第二個是在每個中間件的邏輯代碼中,用于調(diào)用下個中間件。

代碼處理

framework/core.go

修改了Core中添加了一個handlers包含中間件的方法

type Core struct {
	router map[string]*Tree
	handles []ControllerHandler  // 因為包含中間件 所以是多個集合
}
// 在請求邏輯處理的函數(shù)中,添加上我們的next循環(huán)處理中間件的方法
func (c Core) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
	ctx := NewContext(request, writer)
	handlers := c.FindRouteByRequest(request)
	if handlers== nil {
		ctx.Json(404, "router not found ")
		return
	}
  // 先設(shè)置該core添加的中間件方便next去調(diào)用執(zhí)行
	ctx.SetHandler(handlers)
	if err:=ctx.Next();err!=nil{
		ctx.Json(500, "server Interval")
		return
	}
}

上面不僅是加上了這個結(jié)構(gòu)體成員變量,還要處理一下Get等處理方法

將接收的函數(shù)ControllerHandler改為可以接受多個!,然后處理過程將所有中間件都傳給addroute 中去設(shè)置在最后一個映射節(jié)點下!**這樣在我們請求對應(yīng)的路由方法時,就回去執(zhí)行路由最后一個節(jié)點下的所有中間件方法!**下面是例子Get方法:同理Post,Put,Delete

// 注冊Get方法
func (c *Core) Get(pattern string, handler ...ControllerHandler) {
    str :=""
	if 	strings.HasPrefix(pattern,"/"){
		strs:=strings.SplitN(pattern,"/",2)
		str=strs[1]
		log.Println("去除首字符/",str)
	}
	url := strings.ToUpper(str)
	allHandlers:=append(c.handles,handler...)
	log.Println("進來了",url)
	if err := c.router[GET].AddRoute(url, allHandlers); err != nil {
		log.Fatal("add router error:", err)
	}
}

還要加一個方法方便我們在注冊函數(shù)的使用去使用中間件!

func (c *Core)Use(middlewares ...ControllerHandler){
   c.handles=middlewares
}

framework/group.go

其實和上面的core修改方向差不多,都是加上成員變量中間件集合!

type Group struct {
   core   *Core //
   perfix string // 自身前綴
   handler []ControllerHandler
}
//IGroup 代表前綴分組
type IGroup interface {
	Get(string, ...ControllerHandler)
	Post(string, ...ControllerHandler)
	Delete(string, ...ControllerHandler)
	Put(string, ...ControllerHandler)
	Use(middlewares ...ControllerHandler)
}
// 獲得中間件集合
func (g Group)getMiddlewares()[]ControllerHandler{
	if g.handler==nil{
		g.handler=make([]ControllerHandler,0)
	}
	return g.handler
}
// 支持傳入多個中間件
func (g Group) Get(s string, handler ...ControllerHandler) {
	url := g.perfix + s
	allHandlers := append(g.getMiddlewares(), handler...)
	g.core.Get(url, allHandlers...)
}

也添加一個支持添加組的中間件

func (g *Group)Use(middlewares ...ControllerHandler){
   g.handler=middlewares
}

framework/node.go

因為支持了可以傳入多個中間件集合,那么node存放的處理器方法也需要改為切片,那么對應(yīng)下面有以下改動!

// 代表節(jié)點
type node struct {
   isLast  bool              // 代表這個節(jié)點是否可以成為最終的路由規(guī)則。 該節(jié)點是否能成為一
   segment string            // url 中的字符串,代表這個節(jié)點表示的路由中某個段的字符串
   handler []ControllerHandler // 代表這個節(jié)點中包含的控制器,用于最終加載調(diào)用
   childes []*node           // 代表這個節(jié)點下的子節(jié)點
}

將對應(yīng)的handler之前的代碼修改為支持切片多個即可!

func (tree *Tree) AddRoute(url string, handler []ControllerHandler) error {<!--{C}%3C!%2D%2D%20%2D%2D%3E-->...}

framework/context.go

下面來看看context中的Next方法是如何寫的?

type Context struct {
	Request        *http.Request
	ResponseWriter http.ResponseWriter
	hasTimeOut     bool // 是否超時標記位
	writerMux      *sync.Mutex
	// 當前請求的handler鏈條
	handlers []ControllerHandler
	index    int // 請求調(diào)用到的方法下標   每執(zhí)行一個向后+1
}
/*
Next() 函數(shù)會在框架的兩個地方被調(diào)用:
這里要注意,index 下標表示當前調(diào)用 Next 要執(zhí)行的控制器序列,它的初始值應(yīng)該為-1,每次調(diào)用都會自增 1,這樣才能保證第一次調(diào)用的時候 index 為 0,定位到控制器鏈條的下標為 0 的控制器,即第一個控制器。
在框架文件夾 context.go 的初始化 Context 函數(shù)中,代碼如下:
   第一個是在此次請求處理的入口處,即 Core 的 ServeHttp;
   第二個是在每個中間件的邏輯代碼中,用于調(diào)用下個中間件
*/
func (ctx *Context) Next() error {
   ctx.index++
   if ctx.index < len(ctx.handlers) {
      if err := ctx.handlers[ctx.index](ctx); err != nil {
         return err
      }
   }
   return nil
}
// 設(shè)置可可執(zhí)行方法
func (ctx *Context)SetHandler(fn []ControllerHandler){
	if ctx.handlers==nil{
		ctx.handlers=make([]ControllerHandler,0)
	}
	ctx.handlers=append(ctx.handlers,fn...)
}

中間件例子

新建一個middlerware文件夾,然后里面創(chuàng)建文件寫下我們的文件夾

比如我們這個處理錯誤的中間件,

// recovery機制,將協(xié)程中的函數(shù)異常進行捕獲
func Recovery() framework.ControllerHandler { // 使用函數(shù)回調(diào)
   return func(c *framework.Context) error {
      // 核心在增加這個recover機制,捕獲c.Next()出現(xiàn)的panic
      defer func() {
         if err := recover(); err != nil {
            c.Json(500, err)
         }
      }()
      // 使用next執(zhí)行具體的業(yè)務(wù)邏輯
      c.Next()
      return nil
   }
}
// 例子1
func Test1()framework.ControllerHandler{
	return func(c *framework.Context) error {
		log.Println("middleware test1")
		c.Next()
		log.Println("middleware end test1")
		return nil
	}
}
// 例子2
func Test2()framework.ControllerHandler{
	return func(c *framework.Context) error {
		log.Println("middleware test2")
		c.Next()
		log.Println("middleware end test2")
		return nil
	}
}

實際使用

可以如同像gin框架一樣進行用use注冊進我們的中間件!實戰(zhàn)結(jié)束~

func registerRouter(core *framework.Core) {
   print(111)
   // 設(shè)置控制器
   core.Use(middleware.Recovery())
   core.Get("/foo", FooController)
   core.Get("/user/login", framework.TimeOutController(UserLoginController,time.Second*2))
   core.Use(
      middleware.Test1(),
      middleware.Test2(),
   )
   subjectApi := core.Group("/subject")
   subjectApi.Use(middleware.Test2())
   {
      subjectApi.Get("/list/all", SubjectListController)
      subjectApi.Post("/add", SubjectListController)
      subjectApi.Delete("/:id", SubjectListController)
      subjectApi.Put("/:id", SubjectListController)
      subjectApi.Get("/:id", SubjectListController)
   }
}

到此這篇關(guān)于Golang中間件設(shè)計提升HTTP服務(wù)的文章就介紹到這了,更多相關(guān)Golang中間件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Golang中的關(guān)鍵字(defer、:=、go?func())詳細解讀

    Golang中的關(guān)鍵字(defer、:=、go?func())詳細解讀

    這篇文章主要介紹了Golang中的關(guān)鍵字(defer、:=、go?func())詳細解讀,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-04-04
  • Go標準庫http與fasthttp服務(wù)端性能對比場景分析

    Go標準庫http與fasthttp服務(wù)端性能對比場景分析

    這篇文章主要介紹了Go標準庫http與fasthttp服務(wù)端性能比較,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-06-06
  • 簡化Go開發(fā)提高生產(chǎn)力的強大工具及使用詳解

    簡化Go開發(fā)提高生產(chǎn)力的強大工具及使用詳解

    作為?Go?開發(fā)人員,應(yīng)該都知道維持簡潔高效開發(fā)工作流程的重要性,為了提高工作效率和代碼質(zhì)量,簡化開發(fā)流程并自動執(zhí)行重復(fù)性任務(wù)至關(guān)重要,在本文中,我們將探討一些強大的工具和技術(shù),它們將簡化?Go?開發(fā)過程,助力您的編碼之旅
    2023-10-10
  • 一文解析 Golang sync.Once 用法及原理

    一文解析 Golang sync.Once 用法及原理

    這篇文章主要介紹了一文解析 Golang sync.Once 用法及原理,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-08-08
  • Go語言HTTPServer開發(fā)的六種方式小結(jié)

    Go語言HTTPServer開發(fā)的六種方式小結(jié)

    Golang的Server開發(fā)顯得非常簡單,有很多種方式,本文就介紹了Go語言HTTPServer開發(fā)的六種方式,具有一定的參考價值,感興趣的可以了解一下
    2021-11-11
  • 一步步教你打造高效可靠的Go庫

    一步步教你打造高效可靠的Go庫

    這篇文章主要介紹了一步步教你打造高效可靠的Go庫的相關(guān)資料,需要的朋友可以參考下
    2023-11-11
  • golang hack插件開發(fā)動態(tài)鏈接庫實例探究

    golang hack插件開發(fā)動態(tài)鏈接庫實例探究

    這篇文章主要為大家介紹了golang hack插件開發(fā)動態(tài)鏈接庫實例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2024-01-01
  • Windows10系統(tǒng)下安裝Go環(huán)境詳細步驟

    Windows10系統(tǒng)下安裝Go環(huán)境詳細步驟

    Go語言是谷歌推出的一款全新的編程語言,可以在不損失應(yīng)用程序性能的情況下極大的降低代碼的復(fù)雜性,這篇文章主要給大家介紹了關(guān)于Windows10系統(tǒng)下安裝Go環(huán)境的詳細步驟,需要的朋友可以參考下
    2023-11-11
  • Golang通道的無阻塞讀寫的方法示例

    Golang通道的無阻塞讀寫的方法示例

    這篇文章主要介紹了Golang通道的無阻塞讀寫的方法示例,詳細的介紹了哪些情況會存在阻塞,以及如何使用select解決阻塞,非常具有實用價值,需要的朋友可以參考下
    2018-11-11
  • Go語言kube-scheduler深度剖析開發(fā)之scheduler初始化

    Go語言kube-scheduler深度剖析開發(fā)之scheduler初始化

    這篇文章主要介紹了Go語言kube-scheduler深度剖析開發(fā)之scheduler初始化實現(xiàn)過程示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-04-04

最新評論