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中间件等。
中间件定义
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
}
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)
}