学习Go语言Web框架Gee总结--中间件Middleware(五)

学习Go语言Web框架Gee总结--中间件Middleware


网站学习来源: Gee

在Go语言中,web框架的中间件是一种非常常见的概念,它允许开发人员在处理HTTP请求和响应之间插入额外的逻辑。中间件可以用于处理日志记录、身份验证、授权、错误处理等

中间件通常是一个函数,它接受一个http.Handler作为参数,并返回一个新的http.Handler。这样,当一个HTTP请求到达时,它会依次经过一系列的中间件处理,每个中间件都可以在请求被处理之前或之后执行一些额外的逻辑

首先,给context.go添加两个参数

type Context struct {
	// origin objects
	Writer http.ResponseWriter
	Req    *http.Request
	// request info
	Path   string
	Method string
	Params map[string]string
	// response info
	StatusCode int
	// middleware
	handlers []HandlerFunc
	index    int
}

其中handlers []HandlerFunc 是一个存储了多个HandlerFunc函数的切片(slice)。HandlerFunc是一个类型,它是一个接收一个Context作为参数的函数。这意味着handlers切片中存储了多个中间件函数,每个中间件函数都可以对请求进行处理或者添加一些额外的逻辑

index int 则是用来记录当前处理到了handlers切片中的哪个中间件函数。当处理请求时,会依次调用handlers中的函数,index会记录当前调用到了哪个中间件函数,以便在处理完当前中间件后能够调用下一个中间件

通过这样的设计,可以实现在处理请求前后依次执行多个中间件函数的功能,而不需要在每个路由处理器中都编写相同的逻辑。这种设计模式使得代码更加模块化和可复用,也更容易维护

在middleware/gee/context.go中两个函数

func newContext(w http.ResponseWriter, req *http.Request) *Context {
	return &Context{
		Path:   req.URL.Path,
		Method: req.Method,
		Req:    req,
		Writer: w,
		index:  -1,
	}
}

func (c *Context) Next() {
	c.index++
	s := len(c.handlers)
	for ; c.index < s; c.index++ {
		c.handlers[c.index](c)
	}
}

这两个函数是用于创建和处理上下文的中间件机制的关键部分。

首先,func newContext(w http.ResponseWriter, req http.Request) Context 函数是用来创建一个新的上下文对象的。它接受一个http.ResponseWriter和一个http.Request作为参数,然后返回一个新的Context对象。在这个函数中,我们将请求的路径、方法、请求对象和响应对象等信息存储到Context结构体中,并将index初始化为-1,表示还没有开始执行中间件

接下来,func (c *Context) Next() 函数是用来触发执行下一个中间件的。在这个函数中,我们首先将index加1,然后遍历handlers切片中的中间件函数,依次调用每个中间件函数。在调用每个中间件函数时,会将当前的上下文对象c作为参数传递进去,以便中间件函数可以对请求进行处理

通过这两个函数的配合,可以实现在处理请求时依次执行多个中间件函数的功能。当调用Next函数时,会从当前index开始,依次调用handlers中的中间件函数,直到所有的中间件函数都被执行完毕。

举个例子,定义Use函数,将中间件应用到某个 Group

// Use is defined to add middleware to the group
func (group *RouterGroup) Use(middlewares ...HandlerFunc) {
	group.middlewares = append(group.middlewares, middlewares...)
}

func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	var middlewares []HandlerFunc
	for _, group := range engine.groups {
		if strings.HasPrefix(req.URL.Path, group.prefix) {
			middlewares = append(middlewares, group.middlewares...)
		}
	}
	c := newContext(w, req)
	c.handlers = middlewares
	engine.router.handle(c)
}

首先,Use 方法是定义在 RouterGroup 结构体上的,它用于将中间件添加到特定的路由分组中。在这个方法中,我们将传入的中间件函数(HandlerFunc)添加到 group.middlewares 切片中,这样就可以将中间件与特定的路由分组关联起来

接下来,ServeHTTP 方法是 Engine 结构体的一个方法,用于处理HTTP请求。在这个方法中,我们首先创建一个空的中间件切片 middlewares。然后,我们遍历 engine.groups,也就是所有的路由分组,检查当前请求的路径是否以路由分组的前缀开头。如果是的话,就将该路由分组中的中间件添加到 middlewares 中

接着,我们创建一个新的上下文对象 c,并将刚刚收集到的中间件切片赋值给 c.handlers。最后,我们调用 engine.router.handle(c) 来处理请求,这个函数会依次执行 c.handlers 中的中间件函数

通过这种设计,我们可以将中间件与特定的路由分组进行关联,当请求到来时,会根据请求的路径自动选择合适的中间件。这样就实现了在不同的路由分组中应用不同的中间件,从而实现了更加灵活和可配置的中间件机制

关于middleware/gee/router.go中的handle函数

func (r *router) handle(c *Context) {
	n, params := r.getRoute(c.Method, c.Path)

	if n != nil {
		key := c.Method + "-" + n.pattern
		c.Params = params
		c.handlers = append(c.handlers, r.handlers[key])
	} else {
		c.handlers = append(c.handlers, func(c *Context) {
			c.String(http.StatusNotFound, "404 NOT FOUND: %s\n", c.Path)
		})
	}
	c.Next()
}

handle函数是一个路由处理函数,用于根据请求的方法和路径找到对应的处理函数,并将其添加到上下文对象中的 handlers 切片中

首先,函数签名为 func (r *router) handle(c *Context),表示它是 router 结构体的一个方法,用于处理请求。它接受一个指向 Context 对象的指针作为参数

在函数体内部,首先调用 r.getRoute(c.Method, c.Path) 来根据请求的方法和路径获取对应的路由节点(n)和参数(params)。这个方法会返回匹配的路由节点以及路径参数

接着,通过判断 n 是否为空来确定是否找到了匹配的路由。如果找到了匹配的路由节点,就将 c.Params 设置为获取到的参数,并根据请求方法和路由模式拼接出一个唯一的 key。然后将对应的处理函数(r.handlers[key])添加到 c.handlers 切片中

如果未找到匹配的路由节点,就将一个默认的处理函数添加到 c.handlers 中,该处理函数返回404 Not Found的错误信息

最后,调用 c.Next() 来触发执行下一个中间件

总的来说,这段代码的作用是根据请求的方法和路径找到对应的处理函数,并将其添加到上下文对象中的 handlers 切片中。这样在处理请求时,就可以依次执行这些处理函数,实现请求的处理逻辑

你可能感兴趣的:(gee,学习,golang,后端)