GO自研微服务框架-中间件

这篇具有很好参考价值的文章主要介绍了GO自研微服务框架-中间件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一.中间件

中间件的作用是给应用添加一些额外的功能,但是并不会影响原有应用的编码方式,想用的时候直接添加,不想用可以很轻松的去除,做到所谓的可插拔。

中间件的实现位置在哪里?

  1. 不能耦合在用户的代码中
  2. 需要独立存在,但又能拿到上下文,并能做出影响

位置:在处理器的前后

注意:中间件是一个调用链条,所以在处理真正的业务之前,可能会经过多个中间件

1. 定义中间件

type MiddlewareFunc func(handleFunc HandleFunc)HandleFunc

中间件的执行,定义为组级别。

type routerGroup struct {
	name             string
	handleFuncMap    map[string]map[string]HandleFunc
	handlerMethodMap map[string][]string
	treeNode         *treeNode
	preMiddlewares   []MiddlewareFunc //前置中间件
	postMiddlewares  []MiddlewareFunc //后置中间件
}

2. 通用前置中间件

func (r *routerGroup) PreHandle(middlewareFunc ...MiddlewareFunc) {
	r.preMiddlewares = append(r.preMiddlewares, middlewareFunc...)
}
func (r *routerGroup) methodHandle(h HandleFunc, ctx *Context) {
	//前置中间件
	if r.preMiddlewares != nil {
		for _, middlewareFunc := range r.preMiddlewares {
			h = middlewareFunc(h)
		}
	}
	h(ctx)
	//后置中间件
	for _, middlewareFunc := range r.preMiddlewares {
		h = middlewareFunc(h)
	}
}

func (e *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	e.httpRquestHandler(w, r)
}
func (e *Engine) httpRquestHandler(w http.ResponseWriter, r *http.Request) {
	method := r.Method
	for _, group := range e.routerGroups {
		routerName := SubStringLast(r.RequestURI, "/"+group.name)
		// get/1
		node := group.treeNode.Get(routerName)
		if node != nil && node.isEnd {
			//路由匹配上了
			ctx := &Context{
				W: w,
				R: r,
			}
			handle, ok := group.handleFuncMap[node.routerName][ANY]
			if ok {
				group.methodHandle(handle, ctx)
				handle(ctx)
				return
			}

			handle, ok = group.handleFuncMap[node.routerName][method]
			if ok {
				group.methodHandle(handle, ctx)
				return
			}
			//method 进行匹配
			w.WriteHeader(http.StatusMethodNotAllowed)
			fmt.Fprintf(w, "%s %s not allow\n", r.RequestURI, method)
			return
		}
	}
	w.WriteHeader(http.StatusNotFound)
	fmt.Fprintf(w, "%s not found\n", r.RequestURI)
}

3. 通用后置中间件

func (r *routerGroup) PostHandle(middlewareFunc ...MiddlewareFunc) {
	r.postMiddlewares = append(r.postMiddlewares, middlewareFunc...)
}
func (r *routerGroup) methodHandle(h HandleFunc, ctx *Context) {
	//前置中间件
	if r.preMiddlewares != nil {
		for _, middlewareFunc := range r.preMiddlewares {
			h = middlewareFunc(h)
		}
	}
	h(ctx)
	//后置中间件
	if r.postMiddlewares != nil {
		for _, middlewareFunc := range r.postMiddlewares {
			h = middlewareFunc(h)
		}
	}
	h(ctx)
}

4. 测试

func main() {
	engine := msgo.New()
	g := engine.Group("user")
	//g.Get("/hello", func(ctx *msgo.Context) {
	//	fmt.Fprintf(ctx.W, "%s Get欢迎学习GO自研框架", "lisus2000")
	//})
	g.PreHandle(func(next msgo.HandleFunc) msgo.HandleFunc {
		return func(ctx *msgo.Context) {
			fmt.Println("pre Handle")
			next(ctx)
		}
	})
	g.PostHandle(func(handleFunc msgo.HandleFunc) msgo.HandleFunc {
		return func(ctx *msgo.Context) {
			fmt.Println("post handle")
		}
	})
	g.Get("/hello/get", func(ctx *msgo.Context) {
		fmt.Fprintf(ctx.W, "%s Get欢迎学习GO自研框架", "lisus2000")
	})
	g.Post("/hello", func(ctx *msgo.Context) {
		fmt.Fprintf(ctx.W, "%s Post欢迎学习GO自研框架", "lisus2000")
	})
	g.Post("/info", func(ctx *msgo.Context) {
		fmt.Fprintf(ctx.W, "%s info功能", "lisus2000")
	})
	g.Get("/get/:id", func(ctx *msgo.Context) {
		fmt.Fprintf(ctx.W, "%s get user 路径变量的值", "lisus2000")
	})
	engine.Run()
}

5. 改造后置中间件

中间件的触发是等待用户处理函数的执行,也就是说前置中间件就可以完成后置中间件的功能,所以这里我们去除后置中间件

// 定义路由分组结构
type routerGroup struct {
	name             string
	handleFuncMap    map[string]map[string]HandleFunc
	handlerMethodMap map[string][]string
	treeNode         *treeNode
	middlewares      []MiddlewareFunc
}
func (r *routerGroup) Use(middlewareFunc ...MiddlewareFunc) {
	r.middlewares = append(r.middlewares, middlewareFunc...)
}
func (r *routerGroup) methodHandle(h HandleFunc, ctx *Context) {
   //前置中间件
   if r.middlewares != nil {
      for _, middlewareFunc := range r.middlewares {
         h = middlewareFunc(h)
      }
   }
   h(ctx)
}

测试代码

func main() {
   engine := msgo.New()
   g := engine.Group("user")
   //g.Get("/hello", func(ctx *msgo.Context) {
   // fmt.Fprintf(ctx.W, "%s Get欢迎学习GO自研框架", "lisus2000")
   //})
   g.Use(func(next msgo.HandleFunc) msgo.HandleFunc {
      return func(ctx *msgo.Context) {
         fmt.Println("pre Handle")
         next(ctx)
         fmt.Println("post Handler")
      }
   })
   g.Get("/hello/get", func(ctx *msgo.Context) {
      fmt.Fprintf(ctx.W, "%s Get欢迎学习GO自研框架", "lisus2000")
   })
   g.Post("/hello", func(ctx *msgo.Context) {
      fmt.Fprintf(ctx.W, "%s Post欢迎学习GO自研框架", "lisus2000")
   })
   g.Post("/info", func(ctx *msgo.Context) {
      fmt.Fprintf(ctx.W, "%s info功能", "lisus2000")
   })
   g.Get("/get/:id", func(ctx *msgo.Context) {
      fmt.Fprintf(ctx.W, "%s get user 路径变量的值", "lisus2000")
   })
   engine.Run()
}

6. 路由级别中间件

func (r *routerGroup) methodHandle(name string, mehtod string, h HandleFunc, ctx *Context) {
	//组通用中间件
	if r.middlewares != nil {
		for _, middlewareFunc := range r.middlewares {
			h = middlewareFunc(h)
		}
	}
	//路由级别中间件
	middlewareFuncs := r.middlewaresFuncMap[name][mehtod]
	if middlewareFuncs != nil {
		for _, middlewareFunc := range middlewareFuncs {
			h = middlewareFunc(h)
		}
	}
	h(ctx)
}
func (r *routerGroup) handle(name string, method string, handleFunc HandleFunc, middlewareFunc ...MiddlewareFunc) {
	_, ok := r.handleFuncMap[name]
	if !ok {
		r.handleFuncMap[name] = make(map[string]HandleFunc)
		r.middlewaresFuncMap[name] = make(map[string][]MiddlewareFunc)
	}
	_, ok = r.handleFuncMap[name][method]
	if ok {
		panic("有重复的路由")
	}
	r.handleFuncMap[name][method] = handleFunc
	r.middlewaresFuncMap[name][method] = append(r.middlewaresFuncMap[name][method], middlewareFunc...)
	r.treeNode.Put(name)
}

func (r *routerGroup) Any(name string, handleFunc HandleFunc, middlewareFunc ...MiddlewareFunc) {
	r.handle(name, ANY, handleFunc, middlewareFunc...)
}
func (r *routerGroup) Get(name string, handleFunc HandleFunc, middlewareFunc ...MiddlewareFunc) {
	r.handle(name, http.MethodGet, handleFunc, middlewareFunc...)
}
func (r *routerGroup) Post(name string, handleFunc HandleFunc, middlewareFunc ...MiddlewareFunc) {
	r.handle(name, http.MethodPost, handleFunc, middlewareFunc...)
}
func (r *routerGroup) Delete(name string, handlerFunc HandleFunc, middlewareFunc ...MiddlewareFunc) {
	r.handle(name, http.MethodDelete, handlerFunc, middlewareFunc...)
}
func (r *routerGroup) Put(name string, handlerFunc HandleFunc, middlewareFunc ...MiddlewareFunc) {
	r.handle(name, http.MethodPut, handlerFunc, middlewareFunc...)
}
func (r *routerGroup) Patch(name string, handlerFunc HandleFunc, middlewareFunc ...MiddlewareFunc) {
	r.handle(name, http.MethodPatch, handlerFunc, middlewareFunc...)
}
func (r *routerGroup) Options(name string, handlerFunc HandleFunc, middlewareFunc ...MiddlewareFunc) {
	r.handle(name, http.MethodOptions, handlerFunc, middlewareFunc...)
}
func (r *routerGroup) Head(name string, handlerFunc HandleFunc, middlewareFunc ...MiddlewareFunc) {
	r.handle(name, http.MethodHead, handlerFunc, middlewareFunc...)
}

完整代码如下:

package msgo

import (
   "fmt"
   "log"
   "net/http"
)

const ANY = "ANY"

type HandleFunc func(ctx *Context)

type MiddlewareFunc func(handleFunc HandleFunc) HandleFunc

// 定义路由分组结构
type routerGroup struct {
   name               string
   handleFuncMap      map[string]map[string]HandleFunc
   middlewaresFuncMap map[string]map[string][]MiddlewareFunc
   handlerMethodMap   map[string][]string
   treeNode           *treeNode
   middlewares        []MiddlewareFunc
}

type router struct {
   routerGroups []*routerGroup
}

// Group 分组方法
func (r *router) Group(name string) *routerGroup {
   routerGroup := &routerGroup{
      name:               name,
      handleFuncMap:      make(map[string]map[string]HandleFunc),
      middlewaresFuncMap: make(map[string]map[string][]MiddlewareFunc),
      handlerMethodMap:   make(map[string][]string),
      treeNode:           &treeNode{name: "/", children: make([]*treeNode, 0)},
   }
   r.routerGroups = append(r.routerGroups, routerGroup)
   return routerGroup
}

func (r *routerGroup) Use(middlewareFunc ...MiddlewareFunc) {
   r.middlewares = append(r.middlewares, middlewareFunc...)
}

func (r *routerGroup) methodHandle(name string, mehtod string, h HandleFunc, ctx *Context) {
   //组通用中间件
   if r.middlewares != nil {
      for _, middlewareFunc := range r.middlewares {
         h = middlewareFunc(h)
      }
   }
   //路由级别中间件
   middlewareFuncs := r.middlewaresFuncMap[name][mehtod]
   if middlewareFuncs != nil {
      for _, middlewareFunc := range middlewareFuncs {
         h = middlewareFunc(h)
      }
   }
   h(ctx)
}

func (r *routerGroup) handle(name string, method string, handleFunc HandleFunc, middlewareFunc ...MiddlewareFunc) {
   _, ok := r.handleFuncMap[name]
   if !ok {
      r.handleFuncMap[name] = make(map[string]HandleFunc)
      r.middlewaresFuncMap[name] = make(map[string][]MiddlewareFunc)
   }
   _, ok = r.handleFuncMap[name][method]
   if ok {
      panic("有重复的路由")
   }
   r.handleFuncMap[name][method] = handleFunc
   r.middlewaresFuncMap[name][method] = append(r.middlewaresFuncMap[name][method], middlewareFunc...)
   r.treeNode.Put(name)
}

func (r *routerGroup) Any(name string, handleFunc HandleFunc, middlewareFunc ...MiddlewareFunc) {
   r.handle(name, ANY, handleFunc, middlewareFunc...)
}
func (r *routerGroup) Get(name string, handleFunc HandleFunc, middlewareFunc ...MiddlewareFunc) {
   r.handle(name, http.MethodGet, handleFunc, middlewareFunc...)
}
func (r *routerGroup) Post(name string, handleFunc HandleFunc, middlewareFunc ...MiddlewareFunc) {
   r.handle(name, http.MethodPost, handleFunc, middlewareFunc...)
}
func (r *routerGroup) Delete(name string, handlerFunc HandleFunc, middlewareFunc ...MiddlewareFunc) {
   r.handle(name, http.MethodDelete, handlerFunc, middlewareFunc...)
}
func (r *routerGroup) Put(name string, handlerFunc HandleFunc, middlewareFunc ...MiddlewareFunc) {
   r.handle(name, http.MethodPut, handlerFunc, middlewareFunc...)
}
func (r *routerGroup) Patch(name string, handlerFunc HandleFunc, middlewareFunc ...MiddlewareFunc) {
   r.handle(name, http.MethodPatch, handlerFunc, middlewareFunc...)
}
func (r *routerGroup) Options(name string, handlerFunc HandleFunc, middlewareFunc ...MiddlewareFunc) {
   r.handle(name, http.MethodOptions, handlerFunc, middlewareFunc...)
}
func (r *routerGroup) Head(name string, handlerFunc HandleFunc, middlewareFunc ...MiddlewareFunc) {
   r.handle(name, http.MethodHead, handlerFunc, middlewareFunc...)
}

type Engine struct {
   router
}

func New() *Engine {
   return &Engine{
      router: router{},
   }
}
func (e *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
   e.httpRquestHandler(w, r)
}
func (e *Engine) Run() {
   http.Handle("/", e)
   err := http.ListenAndServe(":8111", nil)
   if err != nil {
      log.Fatal(err)
   }
}

func (e *Engine) httpRquestHandler(w http.ResponseWriter, r *http.Request) {
   method := r.Method
   for _, group := range e.routerGroups {
      routerName := SubStringLast(r.RequestURI, "/"+group.name)
      // get/1
      node := group.treeNode.Get(routerName)
      if node != nil && node.isEnd {
         //路由匹配上了
         ctx := &Context{
            W: w,
            R: r,
         }
         handle, ok := group.handleFuncMap[node.routerName][ANY]
         if ok {
            group.methodHandle(node.routerName, ANY, handle, ctx)
            handle(ctx)
            return
         }

         handle, ok = group.handleFuncMap[node.routerName][method]
         if ok {
            group.methodHandle(node.routerName, method, handle, ctx)
            return
         }
         //method 进行匹配
         w.WriteHeader(http.StatusMethodNotAllowed)
         fmt.Fprintf(w, "%s %s not allow\n", r.RequestURI, method)
         return
      }
   }
   w.WriteHeader(http.StatusNotFound)
   fmt.Fprintf(w, "%s not found\n", r.RequestURI)
}

路由级别测试代码文章来源地址https://www.toymoban.com/news/detail-799697.html

package main

import (
   "fmt"
   "msgo"
)

func Log(next msgo.HandleFunc) msgo.HandleFunc {
   return func(ctx *msgo.Context) {
      fmt.Println("打印请求参数")
      next(ctx)
      fmt.Println("返回执行")
   }
}

func main() {
   engine := msgo.New()
   g := engine.Group("user")
   //g.Get("/hello", func(ctx *msgo.Context) {
   // fmt.Fprintf(ctx.W, "%s Get欢迎学习GO自研框架", "lisus2000")
   //})
   g.Use(func(next msgo.HandleFunc) msgo.HandleFunc {
      return func(ctx *msgo.Context) {
         fmt.Println("pre Handle")
         next(ctx)
         fmt.Println("post Handler")
      }
   })
   g.Get("/hello/get", func(ctx *msgo.Context) {
      fmt.Fprintf(ctx.W, "%s Get欢迎学习GO自研框架", "lisus2000")
   }, Log)
   g.Post("/hello", func(ctx *msgo.Context) {
      fmt.Fprintf(ctx.W, "%s Post欢迎学习GO自研框架", "lisus2000")
   })
   g.Post("/info", func(ctx *msgo.Context) {
      fmt.Fprintf(ctx.W, "%s info功能", "lisus2000")
   })
   g.Get("/get/:id", func(ctx *msgo.Context) {
      fmt.Fprintf(ctx.W, "%s get user 路径变量的值", "lisus2000")
   })
   engine.Run()
}

到了这里,关于GO自研微服务框架-中间件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Go重写Redis中间件 - GO实现TCP服务器

    首先新建一个项目go-redis,将config和lib包放到项目中,config.go用来解析配置,比如端口、功能、DB数;lib包有两个文件夹,分别是logger和sync,其中logger.go是一个日志框架,sync包中的bool.go包装了atomic操作,因为atomic原生没有bool类型,所以将uint32类型改造成bool型的atomic,wait.g

    2024年02月15日
    浏览(83)
  • Go Gin中间件

    Gin是一个用Go语言编写的Web框架,它提供了一种简单的方式来创建HTTP路由和处理HTTP请求。中间件是Gin框架中的一个重要概念,它可以用来处理HTTP请求和响应,或者在处理请求之前和之后执行一些操作。 以下是关于Gin中间件开发的一些基本信息: 中间件的定义 :在Gin中,中

    2024年02月05日
    浏览(48)
  • Go重写Redis中间件 - Go实现Redis集群

    这章的内容是将我们之前实现的单机版的Redis扩充成集群版,给Redis增加集群功能,在增加集群功能之前,我们先学习一下在分布式系统中引用非常广泛的技术一致性哈希,一致性哈希在我们项目里就应用在我们Redis集群的搭建这块 详解一致性哈希 Redis集群需求背景 单台服务

    2024年02月13日
    浏览(45)
  • 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/git

    2024年01月17日
    浏览(42)
  • 使用Go编写HTTP中间件

    在Go语言中,HTTP中间件是一种处理HTTP请求和响应的函数,它可以拦截到请求并对其进行处理,然后再将请求传递给下一个中间件或目标处理程序。HTTP中间件在Web应用程序中非常常见,它提供了一种机制来执行各种任务,例如身份验证、授权、日志记录和错误处理等。 下面是

    2024年01月23日
    浏览(43)
  • Go重写Redis中间件 - Go实现内存数据库

    前面我们实现了一个简单的回发Redis,这里我们要实现一个真正的Redis内核 实现底层Dict数据结构 新建一个datastruct文件夹,放一些我们要用的数据结构,比如Redis的核心起始就是一个map,再新建一个包实现这个map或者叫字典,字典的底层使用的就是map dict.go 写一个Dict接口定义

    2024年02月11日
    浏览(51)
  • Go重写Redis中间件 - Go实现Redis协议解析器

    Redis网络协议详解 在解决完通信后,下一步就是搞清楚 Redis 的协议-RESP协议,其实就是一套类似JSON、Protocol Buffers的序列化协议,也就是我们的客户端和服务端通信的协议 RESP定义了5种格式 简单字符串(Simple String) : 服务器用来返回简单的结果,以\\\"+\\\"开头,\\\"rn\\\"结尾的字符串形

    2024年02月15日
    浏览(51)
  • Go重写Redis中间件 - Go实现Redis持久化

    项目开发到这里,我们的下一步就是实现Redis的持久化落盘功能,Redis是一个内存型的数据库,在之前我们实现的单机版Redis如果把进程杀掉,我们通过GET、SET指令存储的数据都将不复存在,数据只存在内存的map里面,重启之后什么都没有了 我们现在的目标就是把用户发来的指

    2024年02月14日
    浏览(52)
  • go gin 全局中间件,以及设置值

    2024年02月11日
    浏览(38)
  • Gin中间件的详解 ,用Jwt-go 和 Gin 的安全的登陆的中间件

    Gin 在不同的group 设置不同的中间件或者过滤器 Gin 的group下的路由上中间件或过滤器 用Jwt-go 和 Gin 的安全的登陆的中间件 JWT 类,它基本有所有基本功能,包括:GenerateToken,GenerateRefreshToken, ValidateToken, ParseToken 1. Gin 在不同的group 设置不同的中间件或者过滤器 Golang 中的 gin

    2024年02月15日
    浏览(61)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包