返回顶部

5.【go-kit教程】go-kit中间件

go-kit中间件

  • go-kit提供了很多用于构建微服务的组件,包括中间件。中间件是在HTTP请求和响应之间处理请求的一些逻辑,可以用于实现一些通用的功能,例如认证、日志记录、缓存等。

  • 官方中间件定义

    type Middleware func(Endpoint) Endpoint
    
  • 在go-kit中间件可以通过装饰器模式来实现,即在原来的服务之上再加上一层逻辑。Go-Kit中间件通常有三种类型:

    1. 服务(service)中间件:服务中间件是针对服务层面的中间件,可以拦截请求,修改上下文信息,添加一些必要的头信息,以及添加跨域资源共享(CORS)等。

    2. 传输(transport )中间件:传输中间件是针对传输层面的中间件,例如负载均衡器和熔断器等。

    3. 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)
    }
    
    

完整示例代码

posted @ 2023-02-25 22:03  高薪程序员  阅读(198)  评论(0编辑  收藏  举报