go-zero学习笔记(五)

news/2025/2/24 13:14:19

 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)。可以理解为前面是队列,后面是栈。


http://www.niftyadmin.cn/n/5864371.html

相关文章

Future和FutureTask实现类详解以及使用。

前言 Future是Java并发编程中的一个接口,用来表示异步计算的结果。它允许我们提交一个任务,然后之后再去获取结果,或者在结果可用时处理它。 我们需要考虑Future的主要方法。根据文档,Future接口有几个关键方法:isDo…

【HarmonyOS Next】地图使用详解(一)

背景 这系列文章主要讲解鸿蒙地图的使用,当前可以免费使用,并提供了丰富的SDK给开发者去自定义控件开发。目前可以实现个性化显示地图、位置搜索和路径规划等功能,轻松完成地图构建工作。需要注意的是,现在测试只能使用实体手机去…

mongodb的并发优化

MongoDB的锁模式 MongoDB的锁设计 MongoDB的高性能表现离不开它的多粒度锁机制。多粒度主要可以针对不同层级的数据库对象进行枷锁,通过避免全局性的互斥来提升并发能力。从整个数据库层面看,MongoDB的并发锁的分层如下图所示: 从上往下是一…

计算机网络之路由协议(自治系统)

一、自治系统(AS) 自治系统是由同一个技术管理机构管理、使用统一选路策略的一些路由器的集合。它是网络的基本构成单位,每个自治系统是一个独立运营并自主决定与谁交换流量的实体。自治系统内部运行内部网关协议(IGP&#xff09…

【过程控制系统】第一章 过程控制系统的设计和发展趋势,确定系统变量和控制方案

给大家分享我最近的作品 绘画时间:2025/2/23 角色:宫本武藏 Fate/Sumurai Renment 关注作者了解更多 我的其他CSDN专栏 毕业设计 求职面试 大学英语 过程控制系统 工程测试技术 虚拟仪器技术 可编程控制器 工业现场总线 数字图像处理 智能控…

如何在java中用httpclient实现rpc get请求

如果你想用 Java 的 HttpClient 实现 RPC 的 GET 请求,过程会稍微不同,因为 GET 请求通常通过 URL 参数(查询字符串)传递数据,而不是像 POST 那样通过请求体。以下是详细的讲解和示例代码。 1. GET 请求与 RPC 的特点…

具有整合各亚专科医学领域知识能力的AI智能体开发纲要(2025版)

整合各亚专科医学领域知识能力的AI代理的开发与研究 一、引言 1.1 研究背景 在科技飞速发展的当下,人工智能(AI)已成为推动各行业变革的关键力量,医疗领域也不例外。近年来,AI 在医疗行业的应用取得了显著进展,从医学影像诊断到疾病预测,从药物研发到个性化医疗,AI 技…

Unity技术突破

技术深度不足怎么办,不妨从以下几点进行突破: 后续会逐个更新并接入最新项目 内存: 拆装箱 资源引用泄漏static和SO 字符串拼接 协程的yield return内存压力 struct内存对齐 GC: foreach IDisposable控制释放时机 unit…