GO——gin中间件和路由

中间件

参考:https://learnku.com/articles/66234

  • 结构
    • 中间件是函数
    • 中间件函数被放在调用链上
    • 调用链的末尾是路由path对应的函数
  • 执行过程
    • net/http包调用到gin的serverHTTP
      • 参考:go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/gin.go:506
    • 通过path找到路由对应的处理链,赋值给context
      • 参考:go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/gin.go:553
    • 执行c.next()启动链条
问题:中间件函数中为啥要调用next,不调用,能继续执行完后面的中间件吗

参考:https://blog.dianduidian.com/post/gin-中间件next方法原理解析/

  • 可以
  • 即使中间件没有调用next函数,那么后续中间件和handles也会执行
  • 中间件中调用next函数,会先执行后续中间件,然后回到这个中间件,继续执行next函数之后的代码
    • 参考:/Users/didi/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7/context.go:165
      • 这里的c.index是一个共用的值
      • c.handlers[c.index](c)执行的时候可能会变,所以虽然在中间件中有调用next函数,但是中间价并不会重复执行
  • 提前结束,不能使用return,要使用abort
    • abort:c.index = abortIndex
代码参考
复制代码
package main

import (
	"encoding/json"
	"fmt"
)

/****  上下文
 */

// Context 上下文
type Context struct {
	Keys    map[string]interface{}
	handles HandleChain
	index   int
}

type HandleChain []func(ctx *Context)

func (c *Context) Render(resultCode int, data interface{}) {
	d, _ := json.Marshal(data)
	fmt.Println("resultCode:", resultCode, " , data:", string(d))
}

func (c *Context) Next() {
	c.index++
	for c.index < len(c.handles) {
		c.handles[c.index](c)
		c.index++
	}
}

func (c *Context) reset() {
	c.index = -1
}

/** 路由
 */

// router 路由
type router struct {
	Handlers map[string]HandleChain
}

type Group struct {
	Handles HandleChain
}

func (r *router) RegisterRoute(url string, f func(*Context), group Group) () {
	if r.Handlers == nil {
		r.Handlers = make(map[string]HandleChain)
	}
	r.Handlers[url] = append(r.Handlers[url], group.Handles...)
	r.Handlers[url] = append(r.Handlers[url], f)
}

func (g *Group) Use(f func(*Context)) {
	g.Handles = append(g.Handles, f)
}

func (r *router) Run(url string, c *Context) () {
	c.handles = r.Handlers[url]
	c.reset()
	c.Next()
}

/** 业务代码
 */

// PlusController 加法
func PlusController(c *Context) {
	a := c.Keys["a"].(int)
	b := c.Keys["b"].(int)
	c.Render(200, plus(a, b))
}

// plus 加法函数
func plus(a, b int) int {
	return a + b
}

// MultiController 乘法
func MultiController(c *Context) {
	a := c.Keys["a"].(int)
	b := c.Keys["b"].(int)
	c.Render(200, multi(a, b))
}

// multi 加法函数
func multi(a, b int) int {
	return a * b
}

/** 主函数
 */

func main() {
	r := router{}
	group1 := Group{Handles: HandleChain{
		func(ctx *Context) {
			fmt.Println("testMiddle1")
		},
		func(ctx *Context) {
			ctx.Next()
			fmt.Println("testMiddle2")
		},
	}}

	group2 := Group{Handles: HandleChain{
		func(ctx *Context) {
			fmt.Println("testMiddle3")
			ctx.Next()
			fmt.Println("testMiddle4")
		},
	}}

	r.RegisterRoute("*", MultiController,group1)
	r.RegisterRoute("+", PlusController,group2)

	fmt.Println("----------")
	r.Run("*", &Context{Keys: map[string]interface{}{"a": 34, "b": 245}})
	fmt.Println("----------")
	r.Run("+", &Context{Keys: map[string]interface{}{"a": 34, "b": 245}})
}
相关推荐
hackchen4 小时前
Go与JS无缝协作:Goja引擎实战之错误处理最佳实践
开发语言·javascript·golang
争不过朝夕,又念着往昔6 小时前
Go语言反射机制详解
开发语言·后端·golang
Jerry Lau6 小时前
go go go 出发咯 - go web开发入门系列(二) Gin 框架实战指南
前端·golang·gin
Code季风12 小时前
微服务分布式配置中心:Gin Web 服务层与 gRPC 服务层集成 Nacos 实战
分布式·微服务·rpc·架构·go·gin·consul
伍哥的传说14 小时前
H3初识——入门介绍之常用中间件
前端·javascript·react.js·中间件·前端框架·node.js·ecmascript
witton15 小时前
Go语言网络游戏服务器模块化编程
服务器·开发语言·游戏·golang·origin·模块化·耦合
叹一曲当时只道是寻常15 小时前
Softhub软件下载站实战开发(十六):仪表盘前端设计与实现
前端·golang
Jerry Lau15 小时前
go go go 出发咯 - go web开发入门系列(一) helloworld
开发语言·前端·golang
天下一般16 小时前
go入门 - day1 - 环境搭建
开发语言·后端·golang
大P哥阿豪18 小时前
Go defer(二):从汇编的角度理解延迟调用的实现
开发语言·汇编·后端·golang