Golang gin 框架中间件(middleware)实现原理详解

文章详细介绍了中间件的基本概念,将其比喻为解耦业务和非业务代码的钩子函数。在Gin框架中,中间件被用来过滤和处理HTTP请求,通过Use方法注册全局中间件,Handle方法注册处理函数。HandlerFunc是中间件和处理函数的统一接口。中间件的执行通过HandlersChain数组进行,Next和Abort函数用于流程控制。手动实现的简单示例进一步解释了中间件的工作原理。
摘要由CSDN通过智能技术生成

怎么理解中间件(middleware)?

做开发的特别是做后端开发的相信对中间件这个词肯定是很熟悉了,中间件的概念还是比较宽泛的,即使在后端开发领域,也有很多不同的含义。概况起来中间件可以理解为用于解耦业务和非业务代码的钩子函数或者程序。在web框架层面,程序运行到某个阶段自动执行预设的函数,运行完后再回到跳出的那个阶段继续执行原函数。

具体到 gin 框架,官方的说法是传入的HTTP请求可以由中间件链和最终操作来处理。可以理解为中间件是一种过滤路由的机制,也就是http请求来到时先经过中间件,再到具体的处理函数,传入的 HTTP 请求可以由一系列中间件和最终操作来处理,可以在中间件中实现前置和后置处理逻辑。

gin 中间件实现方法分析

1、gin 把中间件和主体函数统一定义为 handleFunc

// HandlerFunc defines the handler used by gin middleware as return value.
type HandlerFunc func(*Context)

// Use attaches a global middleware to the router. i.e. the middleware attached through Use() will be
// included in the handlers chain for every single request. Even 404, 405, static files...
// For example, this is the right place for a logger or error management middleware.
func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
	engine.RouterGroup.Use(middleware...)
	engine.rebuild404Handlers()
	engine.rebuild405Handlers()
	return engine
}

// Handle registers a new request handle and middleware with the given path and method.
// The last handler should be the real handler, the other ones should be middleware that can and should be shared among different routes.
// See the example code in GitHub.
//
// For GET, POST, PUT, PATCH and DELETE requests the respective shortcut
// functions can be used.
//
// This function is intended for bulk loading and to allow the usage of less
// frequently used, non-standardized or custom methods (e.g. for internal
// communication with a proxy).
func (group *RouterGroup) Handle(httpMethod, relativePath string, handlers ...HandlerFunc) IRoutes {
	if matched := regEnLetter.MatchString(httpMethod); !matched {
		panic("http method " + httpMethod + " is not valid")
	}
	return group.handle(httpMethod, relativePath, handlers)
}

无论是是用 use 方法注册中间件,还是用 handle 方法注册主体函数,类型都是 HandlerFunc

2、把所有 handleFunc 放入入一个元素类型为 handleChain 的数组

// HandlerFunc defines the handler used by gin middleware as return value.
type HandlerFunc func(*Context)

// HandlersChain defines a HandlerFunc slice.
type HandlersChain []HandlerFunc

3、从 handleChain 的第一个元素开始执行,中间使用 Next、Abort 等函数来进行流程控制

// Next should be used only inside middleware.
// It executes the pending handlers in the chain inside the calling handler.
// See example in GitHub.
func (c *Context) Next() {
   c.index++
   for c.index < int8(len(c.handlers)) {
      c.handlers[c.index](c)
      c.index++
   }
}

// Abort prevents pending handlers from being called. Note that this will not stop the current handler.
// Let's say you have an authorization middleware that validates that the current request is authorized.
// If the authorization fails (ex: the password does not match), call Abort to ensure the remaining handlers
// for this request are not called.
func (c *Context) Abort() {
	c.index = abortIndex
}

手动实现中间件逻辑程序

参考 gin 实现中间件逻辑的思路,手动实现一个简单的演示程序,如下

package main

import (
	"fmt"
)

const maxIndex = 63

type HandlerFunc func(ctx *context)

type context struct {
	HandlersChain []HandlerFunc
	index         int8
}

func (ctx *context) next() {
	if ctx.index < maxIndex {
		ctx.index++
		ctx.HandlersChain[ctx.index](ctx)
	}
}

func (ctx *context) abort() {
	ctx.index = maxIndex
	fmt.Println("abort...")
}

func (ctx *context) use(f HandlerFunc) {
	ctx.HandlersChain = append(ctx.HandlersChain, f)
}

func (ctx *context) get(relativePath string, f HandlerFunc) {
	ctx.HandlersChain = append(ctx.HandlersChain, f)
}

func (ctx *context) run() {
	ctx.HandlersChain[0](ctx)
}

func main() {
	ctx := &context{}
	ctx.use(middleware1)
	ctx.use(middleware2)
	ctx.get("hahahah", logicFunc)
	ctx.run()
}

func middleware1(ctx *context) {
	fmt.Println("middleware1 begin")
	//ctx.abort()
	ctx.next()
	fmt.Println("middleware1 end")
}

func middleware2(ctx *context) {
	fmt.Println("middleware2 begin")
	ctx.next()
	fmt.Println("middleware2 end")
}

func logicFunc(ctx *context) {
	fmt.Println("logicFunc function")
}

运行结果为

middleware1 begin
middleware2 begin
logicFunc function
middleware2 end
middleware1 end

相信这个简化版的中间件实现肯定可以帮助你理解其中的原理。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

路多辛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值