go 微服务框架kratos使用中间件的方法

 更新时间:2024年05月28日 14:35:23   作者:龙门吹雪  
在go语言中,中间件是一种用于处理http请求的开发模式,允许开发人员在请求到达处理程序之前或之后执行特定的操作,如日志记录、身份验证、错误处理等,这篇文章主要介绍了go 微服务框架kratos使用中间件的方法,需要的朋友可以参考下

一、中间件的概念

在go语言中,中间件是一种用于处理http请求的开发模式,允许开发人员在请求到达处理程序之前或之后执行特定的操作,如日志记录、身份验证、错误处理等。

中间件通常是一个函数,它接收一个 `http.Handler` 作为参数并返回另一个 `http.Handler`。

go源码中 Handler 的定义如下:

type Handler interface {
	ServeHTTP(ResponseWriter, *Request)
}

二、go原生http中使用中间件的方法

使用方法:

1、创建中间件函数,输入参数 http.Handler,输出参数 http.Handler

2、将处理器函数作为参数传入上述中间件函数

3、运用 Handle(pattern string, handler Handler) 等函数将中间件函数绑定到请求路由中

代码示例:

package main
import (
	"fmt"
	"log"
	"net/http"
)
// 日志记录中间件
func loggingMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log.Printf("请求处理之前   Request URI: %s\n", r.RequestURI)
		next.ServeHTTP(w, r)
		log.Printf("处理程序之后进行的操作...\n")
	})
}
// handler 处理函数
func SayHello(w http.ResponseWriter, r *http.Request) {
	fmt.Println("Hello world")
}
func main() {
	//创建一个 HTTP 请求路由器
	mux := http.NewServeMux()
	// 使用日志记录中间件
	mux.Handle("/index", loggingMiddleware(http.HandlerFunc(SayHello)))
	//启动服务,使用创建的 ServeMux
	http.ListenAndServe(":8081", mux)
}

运行效果:

三、go微服务框架Kratos使用中间件的方法

kratos介绍中间件的官网地址:概览 | Kratos

1、内置中间件使用方法

①通过 Middleware(m ...middleware.Middleware) ServerOption 添加所需的中间件

②将上述由中间件组成的 ServerOption 添加到 []http.ServerOption 中

③通过函数 NewServer(opts ...ServerOption) *Server 创建 httpServer

代码示例:

func NewHTTPServer(c *conf.Server, logger log.Logger, blog *service.BlogService) *http.Server {
	opts := []http.ServerOption{
		http.Middleware(
			//使用kratos内置中间件
			recovery.Recovery(),
			tracing.Server(),
			logging.Server(logger),
			validate.Validator(),
		),
	}
	if c.Http.Network != "" {
		opts = append(opts, http.Network(c.Http.Network))
	}
	if c.Http.Addr != "" {
		opts = append(opts, http.Address(c.Http.Addr))
	}
	if c.Http.Timeout != nil {
		opts = append(opts, http.Timeout(c.Http.Timeout.AsDuration()))
	}
	//创建 httpServer 
	srv := http.NewServer(opts...)
	v1.RegisterBlogServiceHTTPServer(srv, blog)
	return srv
}

2、自定义中间件使用方法

①实现 middleware.Middleware 接口,其定义如下:

// Handler defines the handler invoked by Middleware.
type Handler func(ctx context.Context, req interface{}) (interface{}, error)
// Middleware is HTTP/gRPC transport middleware.
type Middleware func(Handler) Handler

中间件中您可以使用 tr, ok := transport.FromServerContext(ctx) 获得 Transporter 实例以便访问接口相关的元信息。

②像添加内置中间件一样,将自定义中间件添加到 http.Middleware 和 []http.ServerOption 中

③通过函数 NewServer(opts ...ServerOption) *Server 创建 httpServer

代码示例:

// auth.go 单元
//自定义 JWT 认证中间件
func JWTAuth(jwtSecret string) middleware.Middleware {
	return func(handler middleware.Handler) middleware.Handler {
		return func(ctx context.Context, req interface{}) (reply interface{}, err error) {
			if tr, ok := transport.FromServerContext(ctx); ok {
				tokenString := tr.RequestHeader().Get("authorization")
				spew.Dump(tokenString)
				//token, err := jwt.ParseWithClaims(tokenString, &jwt.StandardClaims{}, func(token *jwt.Token) (interface{}, error) {
				token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
					// Don't forget to validate the alg is what you expect:
					if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
						return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
					}
					// hmacSampleSecret is a []byte containing your secret, e.g. []byte("my_secret_key")
					return []byte(jwtSecret), nil
				})
				if err != nil {
					log.Fatal(err)
				}
				if claims, ok := token.Claims.(jwt.MapClaims); ok {
					fmt.Println(claims["iss"], claims["exp"])
					//fmt.Println(claims.Issuer, claims.ExpiresAt)
				} else {
					fmt.Println(err)
				}
			}
			return handler(ctx, req)
		}
	}
}
// server/http.go 单元
func NewHTTPServer(c *conf.Server, confAuth *conf.Auth, logger log.Logger, blog *service.BlogService) *http.Server {
	opts := []http.ServerOption{
		http.Middleware(
			//自定义中间件 JWTAuth
			auth.JWTAuth(confAuth.JwtSecrect),
		),
	}
	if c.Http.Network != "" {
		opts = append(opts, http.Network(c.Http.Network))
	}
	if c.Http.Addr != "" {
		opts = append(opts, http.Address(c.Http.Addr))
	}
	if c.Http.Timeout != nil {
		opts = append(opts, http.Timeout(c.Http.Timeout.AsDuration()))
	}
	//创建 httpServer 
	srv := http.NewServer(opts...)
	v1.RegisterBlogServiceHTTPServer(srv, blog)
	return srv
}

3、为特定路由定制中间件的使用方法

使用方法:

对特定路由定制中间件:

server: selector.Server(ms...)

client: selector.Client(ms...)

代码示例:

// server/http.go 单元
// 添加验证白名单
func NewWhiteListMatcher() selector.MatchFunc {
	whiteList := make(map[string]struct{})
	whiteList["/blog.api.v1.Account/Login"] = struct{}{}
	whiteList["/blog.api.v1.Account/Register"] = struct{}{}
	return func(ctx context.Context, operation string) bool {
		if _, ok := whiteList[operation]; ok {
			return false
		}
		return true
	}
}
// server/http.go 单元
func NewHTTPServer(c *conf.Server, confAuth *conf.Auth, logger log.Logger, blog *service.BlogService) *http.Server {
	opts := []http.ServerOption{
		http.Middleware(
			//自定义中间件 JWTAuth
			selector.Server(auth.JWTAuth(confAuth.JwtSecrect)).
				Match(NewWhiteListMatcher()).
				Build(),
		),
	}
	if c.Http.Network != "" {
		opts = append(opts, http.Network(c.Http.Network))
	}
	if c.Http.Addr != "" {
		opts = append(opts, http.Address(c.Http.Addr))
	}
	if c.Http.Timeout != nil {
		opts = append(opts, http.Timeout(c.Http.Timeout.AsDuration()))
	}
	//创建 httpServer 
	srv := http.NewServer(opts...)
	v1.RegisterBlogServiceHTTPServer(srv, blog)
	return srv
}

注意: 定制中间件是通过 operation 匹配,并不是 http 本身的路由!!!

gRPC path 的拼接规则为 /包名.服务名/方法名(/package.Service/Method)

到此这篇关于go 微服务框架kratos使用中间件的方法的文章就介绍到这了,更多相关go 微服务框架kratos使用中间件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Golang学习笔记之延迟函数(defer)的使用小结

    Golang学习笔记之延迟函数(defer)的使用小结

    这篇文章主要介绍了Golang学习笔记之延迟函数(defer),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-12-12
  • Golang开发之字符串与切片问题踩坑记录

    Golang开发之字符串与切片问题踩坑记录

    字符串和切片,都是golang常用的两种内置数据类型,最近在日常工作中,遇到了一个字符串切片导致的问题,记录一下排查问题的过程,避免后续在这种场景上踩坑
    2023-07-07
  • Golang断言判断值类型的实现方法

    Golang断言判断值类型的实现方法

    这篇文章主要介绍了Golang断言判断值类型的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • 详解Golang如何比较两个slice是否相等

    详解Golang如何比较两个slice是否相等

    开发中常会遇到需要比较两个slice包含的元素是否完全相等的情况,我们通常会通过两种方法去比较切片是否相等。这里通过几个示例来看一下这两种方法,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助
    2022-11-11
  • Golang巧用defer进行错误处理的方法

    Golang巧用defer进行错误处理的方法

    错误处理是程序的重要组成部分,有效且优雅的处理错误是大多数程序员的追求,下面这篇文章主要给大家介绍了关于Golang中巧用defer进行错误处理的方法,文中通过示例介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2017-05-05
  • Go语言七篇入门教程一简介初识

    Go语言七篇入门教程一简介初识

    本篇是Go语言七篇入门系列第一篇Go语言初识及简单介绍,从现在开始一起打开Go语言的学习大门吧,希望能够有所帮助,祝大家多多进步
    2021-11-11
  • Go语言Zap日志库使用教程

    Go语言Zap日志库使用教程

    在项目开发中,经常需要把程序运行过程中各种信息记录下来,有了详细的日志有助于问题排查和功能优化;但如何选择和使用性能好功能强大的日志库,这个就需要我们从多角度考虑
    2023-02-02
  • Go语言中的并发模式你了解了吗

    Go语言中的并发模式你了解了吗

    工作中查看项目代码,发现会存在使用 GO 语言做并发的时候出现各种各样的异常情况,实际上,出现上述的情况,还是因为我们对于 GO 语言的并发模型和涉及的 GO 语言基础不够扎实,所以本文小编就来带大家深入了解下Go语言中的并发模式吧
    2023-08-08
  • go带缓冲chan实现消息队列功能

    go带缓冲chan实现消息队列功能

    本文主要介绍了go带缓冲chan实现消息队列功能,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-02-02
  • Go 热加载之fresh详解

    Go 热加载之fresh详解

    这篇文章主要为大家介绍了Go 热加载之fresh详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08

最新评论