5.【go-kit教程】go-kit中间件
go-kit中间件
-
go-kit提供了很多用于构建微服务的组件,包括中间件。中间件是在HTTP请求和响应之间处理请求的一些逻辑,可以用于实现一些通用的功能,例如认证、日志记录、缓存等。
-
官方中间件定义
type Middleware func(Endpoint) Endpoint
-
在go-kit中间件可以通过装饰器模式来实现,即在原来的服务之上再加上一层逻辑。Go-Kit中间件通常有三种类型:
-
服务(service)中间件:服务中间件是针对服务层面的中间件,可以拦截请求,修改上下文信息,添加一些必要的头信息,以及添加跨域资源共享(CORS)等。
-
传输(transport )中间件:传输中间件是针对传输层面的中间件,例如负载均衡器和熔断器等。
-
enpoint中间件:endpoint 中间件的一种常见方式是使用装饰器模式。可以定义一个函数,该函数接受一个 endpoint 作为参数,返回一个新的 endpoint,该新 endpoint 可以在原始 endpoint 被调用前或后添加一些逻辑。例如:
func MiddlewareOne(next endpoint.Endpoint) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { // 在原始 endpoint 被调用前添加逻辑 // ... // 调用原始 endpoint response, err := next(ctx, request) // 在原始 endpoint 被调用后添加逻辑 // ... return response, err } }
-
-
go-kit提供了一些默认的中间件,例如Logging中间件,它可以记录每个请求的日志信息,包括请求的URL、方法、请求体、响应码和响应体等。还有一些其他的中间件,例如Circuit Breaker中间件、Rate Limiter中间件等。
日志中间件
1. transport 日志中间件
-
中间件定义
func LoggingMiddleware(logger log.Logger) endpoint.Middleware { return func(next endpoint.Endpoint) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { logger.Log("msg", "starting request") // 计算请求处理时间 start := time.Now() defer func() { logger.Log("msg", "finished request", "took", time.Since(start)) }() // 调用下一个 endpoint response, err := next(ctx, request) if err != nil { logger.Log("msg", "request failed", "err", err) return nil, err } logger.Log("msg", "request succeeded") return response, nil } } }
-
项目引用实例
/** * @date: 2023/2/22 * @desc: */ package transports import ( "context" "github.com/go-kit/kit/log" grpctranspoint "github.com/go-kit/kit/transport/grpc" "my-kit-demo/endpoints" "my-kit-demo/middlewares" "my-kit-demo/proto" ) type pingGRPCServer struct { sayPing grpctranspoint.Handler proto.UnimplementedPingServer } func (s *pingGRPCServer) SayPing(ctx context.Context, req *proto.ReqMsg) (*proto.ResMsg, error) { _, resp, err := s.sayPing.ServeGRPC(ctx, req) if err != nil { return nil, err } return resp.(*proto.ResMsg), nil } func NewPingGRPCServer(ept endpoints.PingEndpoint, logger log.Logger) proto.PingServer { options := []grpctranspoint.ServerOption{} newEndpoint := middlewares.LoggingMiddleware(logger)(ept.SayPing) // 引入日志中间件 return &pingGRPCServer{ sayPing: grpctranspoint.NewServer( newEndpoint, decodeGRPCPingRequest, encodeGRPCPingResponse, options..., ), } } func decodeGRPCPingRequest(_ context.Context, request interface{}) (interface{}, error) { req := request.(*proto.ReqMsg) return &proto.ReqMsg{Msg: req.Msg}, nil } func encodeGRPCPingResponse(_ context.Context, response interface{}) (interface{}, error) { res := response.(*proto.ResMsg) return &proto.ResMsg{Msg: res.Msg}, nil }
2. service 中间件
service 中间件要为每一个service创建一个中间件,因为中间件要重写我们定义service接口的方法
-
中间件定义
func LoggingMiddleware(logger log.Logger) ServiceMiddleware { return func(next MyService) MyService { return loggingMiddleware{logger, next} } } type loggingMiddleware struct { logger log.Logger next MyService } func (mw loggingMiddleware) MyMethod(ctx context.Context, req Request) (resp Response, err error) { defer func(start time.Time) { mw.logger.Log( "method", "MyMethod", "input", req, "output", resp, "err", err, "took", time.Since(start), ) }(time.Now()) // 调用下一个方法 return mw.next.MyMethod(ctx, req) }
-
项目引用
/** * @date: 2023/2/22 * @desc: */ package middlewares import ( "context" "github.com/go-kit/kit/log" "my-kit-demo/services" "time" ) func LoggingPingServiceMiddleware(logger log.Logger) func(services.PingService) services.PingService { return func(next services.PingService) services.PingService { return loggingMiddleware{logger, next} } } type loggingMiddleware struct { logger log.Logger next services.PingService } func (lm loggingMiddleware) SayPing(ctx context.Context, req string) (resp string, err error) { defer func(start time.Time) { lm.logger.Log( "method", "PingService", "input", req, "output", resp, "err", err, "took", time.Since(start), ) }(time.Now()) // 调用下一个方法 return lm.next.SayPing(ctx, req) }