当前位置: 首页 > news >正文

go-zero学习笔记(五)

 api自定义中间件


1. 修改.api文件


	syntax="v1"
	
	type (
		GetInfoReq {
			IDs []string `json:"IDs"`
		}
	
		GetInfoData {
			ID     string `json:"ID"`
			Name   string `json:"Name"`
			MD5    string `json:"md5"`
			Size   int64  `json:"Size"`
			Uptime int64  `json:"uptime"`
		}
	
		GetInfoResp {
			Data      []*GetInfoData `json:"data"`
			Msg       string         `json:"msg"`
			Code      int64          `json:"code"`
			RequestID string         `json:"requestId"`
		}
	)
	
	// 修饰其紧挨的service块,且一个server块只能修饰一个service块
	@server(
		prefix: api/demo/v1         
		group: demo                 
		middleware: CheckMiddleware, TestMiddleware  
	)
	service demo-api {
		@doc(
			summary: "信息获取"
		)
		@handler GetInfoHandler
		post /Info/get (GetInfoReq) returns (GetInfoResp)
	}

         在server块中新增checkMiddleware, testMiddleware  两个中间件,其中checkMiddleware, testMiddleware为中间件名称。


    middleware: CheckMiddleware, TestMiddleware  

        之前说过, server修饰的是其紧挨的service 块,因此在server块中新增中间件,会为其紧挨的service 块中的每个接口都增加中间件checkMiddleware, testMiddleware,因此,请注意作用域,如何部分接口不需要中间件,请分开定义。

2. 执行命令
 

goctl api go -api ./api/demo.api -dir . -style gozero

  生成关于中间件部分的代码主要如下:

3. 编写中间件逻辑代码

        接下来就可以在Handle函数中添加对应的逻辑了,在next(w, r)前后都可以添加,

package middleware

import "net/http"

type CheckMiddleware struct {
}

func NewCheckMiddleware() *CheckMiddleware {
	return &CheckMiddleware{}
}

func (m *CheckMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// TODO generate middleware implement function, delete after code implementation

		// Passthrough to next handler if need

		/******
		请求到来后需要执行的代码
		代码块a
		*/

		next(w, r)

		/******
		请求返回时需要执行的代码
		代码块A
		*/
	}
}

package middleware

import "net/http"

type TestMiddleware struct {
}

func NewTestMiddleware() *TestMiddleware {
	return &TestMiddleware{}
}

func (m *TestMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// TODO generate middleware implement function, delete after code implementation

		// Passthrough to next handler if need
		/******
		请求到来后需要执行的代码
		代码块b
		*/
		
		next(w, r)
		
		/******
		请求返回时需要执行的代码
		代码块B
		*/
	}
}

        如果你需要外部传递参数,可以在对应的结构体中添加,如在TestMiddleware 结构体中添加变量,并在New函数中传入

type TestMiddleware struct {
	Num   int
	Class string
}

func NewTestMiddleware(num int, class string) *TestMiddleware {
	return &TestMiddleware{
		Num:   num,
		Class: class,
	}
}

4. 修改servicecontext.go文件

通过函数间的调用关系,可以发现,中间件中的Handle函数是在servicecontext.go被调用的。

type ServiceContext struct {
	Config          config.Config
	CheckMiddleware rest.Middleware
	TestMiddleware  rest.Middleware
	DemoRpc         demo.DemoClient
}

func NewServiceContext(c config.Config) *ServiceContext {
	return &ServiceContext{
		Config:          c,
		CheckMiddleware: middleware.NewCheckMiddleware().Handle,
		TestMiddleware:  middleware.NewTestMiddleware(5, "rongyu").Handle,
		DemoRpc:         demo.NewDemoClient(zrpc.MustNewClient(c.DemoRpcConf).Conn()),
	}
}

        如果,你对中间件的结构体进行了修改,新增了变量,则需要修改上述代码的NewTestMiddleware处将值传进去。

        通过阅读代码可以发现,中间件在ServiceContext 中定义,在main函数中初始化,随后被传入到RegisterHandlers中使用。

func main() {
	flag.Parse()

	var c config.Config
	conf.MustLoad(*configFile, &c)

	server := rest.MustNewServer(c.RestConf)
	defer server.Stop()

	ctx := svc.NewServiceContext(c)
	handler.RegisterHandlers(server, ctx)

	fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
	server.Start()
}


func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
	server.AddRoutes(
		rest.WithMiddlewares(
			[]rest.Middleware{serverCtx.CheckMiddleware, serverCtx.TestMiddleware},
			[]rest.Route{
				{
					Method:  http.MethodPost,
					Path:    "/Info/get",
					Handler: demo.GetInfoHandler(serverCtx),
				},
			}...,
		),
		rest.WithPrefix("/api/demo/v1"),
	)
}


5. 多个中间件的执行顺序

        在上述介绍中, 一共写了四段代码a、A、b、B,中间件的顺序是CheckMiddleware, TestMiddleware, 那么代码a、A、b、B的被执行的先后顺序是a、b、B、A。类似于一个U型仓,最底下是 next(w, r)。可以理解为前面是队列,后面是栈。

相关文章:

  • 【Web RCE 漏洞常见类型】
  • [git]GIT提交带GPG签名改动到GITEE的配置方法
  • 骁勇善战的量化利器:多因子模型【量化理论】
  • Vue 中单向数据流原则
  • 2025-spring boot 之多数据源管理
  • HyperGraph(超图)
  • 【Redis数据结构】ziplist 压缩列表
  • nginx 反向代理 配置请求路由
  • 【网络编程】广播和组播
  • 【RK3588嵌入式图形编程】-SDL2-构建交互式按钮
  • 基于python+django的宠物商店-宠物管理系统源码+运行步骤
  • J4打卡—— ResNet 和 DenseNet结合实现鸟类分类
  • 用AI写游戏3——deepseek实现kotlin android studio greedy snake game 贪吃蛇游戏
  • 【quicker】调节PPT指定字号字体大小/快速调节WPS的PPT字体大小
  • 三级分类bug解决
  • 作用域的知识点总结
  • Day6 高精度加减算法+洛谷讲解
  • 开源RAG主流框架有哪些?如何选型?
  • 算法系列之分治算法
  • 从底层驱动到 OpenCV:深入解析 Linux 摄像头完整技术栈
  • 上海:以税务支持鼓励探索更多的创新,助力企业出海
  • 媒体:酒店、民宿临时毁约涨价,怎么管?
  • 聚焦各领域顶尖工匠,《上海工匠》第十季于五一播出
  • 国台办:台商台企有信心与国家一起打赢这场关税战
  • 招商蛇口:一季度营收约204亿元,净利润约4.45亿元
  • 华夏幸福:去年营业收入237.65亿元,同比减亏12亿元