3步搞定Kratos中间件开发:从0到1实现自定义拦截器
你是否还在为微服务中的通用功能重复编码?日志记录、权限验证、超时控制这些横切关注点,正在消耗你大量开发时间。本文将带你通过3个步骤掌握Kratos中间件开发,用拦截器模式优雅解决这些问题,让业务代码更专注于核心逻辑。
读完本文你将获得:
- 理解Kratos中间件的设计原理与调用链
- 掌握自定义中间件的标准实现模板
- 学会3种场景化注册方式与最佳实践
- 获得性能监控中间件的完整代码示例
中间件核心原理
Kratos中间件基于经典的责任链模式设计,通过嵌套函数实现请求的层层拦截与处理。核心接口定义在middleware/middleware.go中:
// Handler defines the handler invoked by Middleware.
type Handler func(ctx context.Context, req any) (any, error)
// Middleware is HTTP/gRPC transport middleware.
type Middleware func(Handler) Handler
中间件本质是接收一个Handler并返回新Handler的高阶函数。当多个中间件组合时,形成一个调用链条:
框架提供的Chain函数用于组合多个中间件,注意执行顺序是从最后一个到第一个:
// Chain returns a Middleware that specifies the chained handler for endpoint.
func Chain(m ...Middleware) Middleware {
return func(next Handler) Handler {
for i := len(m) - 1; i >= 0; i-- {
next = mi
}
return next
}
}
自定义中间件实现
以实用的请求耗时监控中间件为例,我们需要记录每个请求的处理时间并输出日志。完整实现遵循固定模板:
// 定义中间件构造函数,支持传入参数
func Timing(logger log.Logger) middleware.Middleware {
// 返回Middleware函数
return func(handler middleware.Handler) middleware.Handler {
// 返回新的Handler函数
return func(ctx context.Context, req any) (reply any, err error) {
// 前置处理:记录开始时间
startTime := time.Now()
// 调用下一个中间件或业务逻辑
reply, err = handler(ctx, req)
// 后置处理:计算耗时并记录
duration := time.Since(startTime)
log.NewHelper(logger).Infow(
"request processed",
"duration", duration,
"path", transport.FromContext(ctx).Operation(),
)
return reply, err
}
}
}
这个模板包含三个关键部分:
- 构造函数:接收外部依赖(如日志器)
- 中间件函数:接收并包装Handler
- 处理函数:实现具体的拦截逻辑
Kratos内置了多种中间件实现,如middleware/logging/logging.go提供的日志中间件,你可以参考其实现复杂功能。
三种注册方式
1. 全局注册
通过Chain函数组合中间件,并在创建HTTP服务器时注册为全局中间件:
import (
"github.com/go-kratos/kratos/v2/middleware"
"github.com/go-kratos/kratos/v2/transport/http"
)
func main() {
// 创建中间件链
var m middleware.Middleware = middleware.Chain(
logging.Server(logger),
timing.Timing(logger), // 自定义中间件
)
// 创建HTTP服务器并注册
srv := http.NewServer(
http.Address(":8080"),
http.Middleware(m), // 全局注册
)
}
2. 路由级注册
通过HTTP服务器的Use方法,可以为特定路由模式注册中间件:
// 为/helloworld.v1.Greeter服务注册中间件
srv.Use("/helloworld.v1.Greeter/*", auth.Middleware())
// 为特定方法注册中间件
srv.Use("/helloworld.v1.Greeter/SayHello", ratelimit.Middleware())
路由匹配规则支持:
/*:匹配所有路由/service/*:匹配服务下所有方法/service/method:匹配特定方法
3. 应用级注册
在创建Kratos应用时,可以通过选项注册应用生命周期中间件:
import "github.com/go-kratos/kratos/v2"
func main() {
app := kratos.New(
kratos.Name("helloworld"),
kratos.Middleware(
tracing.Server(),
),
)
}
完整示例:性能监控中间件
下面实现一个功能完整的性能监控中间件,包含耗时统计、错误率计算和阈值告警:
package metrics
import (
"context"
"time"
"github.com/go-kratos/kratos/v2/log"
"github.com/go-kratos/kratos/v2/middleware"
"github.com/go-kratos/kratos/v2/transport"
)
// Config 中间件配置
type Config struct {
SlowThreshold time.Duration // 慢请求阈值
}
// Server 创建性能监控中间件
func Server(logger log.Logger, cfg Config) middleware.Middleware {
return func(handler middleware.Handler) middleware.Handler {
return func(ctx context.Context, req any) (reply any, err error) {
// 获取请求信息
info, ok := transport.FromContext(ctx)
if !ok {
return handler(ctx, req)
}
start := time.Now()
reply, err = handler(ctx, req)
duration := time.Since(start)
// 记录基本信息
logContent := log.Fields{
"operation": info.Operation(),
"duration": duration,
"code": extractCode(err),
}
// 慢请求告警
if duration > cfg.SlowThreshold {
log.NewHelper(logger).Warnw("slow request detected", logContent)
} else {
log.NewHelper(logger).Infow("request processed", logContent)
}
return reply, err
}
}
}
// 从错误中提取状态码
func extractCode(err error) int {
if err == nil {
return 200
}
// 错误码提取逻辑...
return 500
}
注册与使用:
// 创建配置
cfg := metrics.Config{
SlowThreshold: 500 * time.Millisecond,
}
// 注册到HTTP服务器
srv := http.NewServer(
http.Middleware(
metrics.Server(logger, cfg),
),
)
最佳实践
1. 错误处理
中间件中捕获的错误应该使用Kratos标准错误类型:
import "github.com/go-kratos/kratos/v2/errors"
// 错误处理示例
if err != nil {
// 记录错误并包装
log.Errorw("middleware failed", "err", err)
return nil, errors.InternalServer("MIDDLEWARE_ERR", err.Error())
}
2. 上下文传递
使用transport.FromContext和transport.NewContext在中间件间传递信息:
// 设置上下文值
ctx = transport.NewContext(ctx, transport.WithHeader(map[string]string{
"X-Request-ID": uuid.New().String(),
}))
// 获取上下文值
if info, ok := transport.FromContext(ctx); ok {
reqID := info.RequestHeader().Get("X-Request-ID")
}
3. 性能考虑
避免在中间件中执行耗时操作,必要时使用异步处理:
// 异步记录日志,不阻塞主流程
go func() {
defer recover()
metricsClient.RecordDuration(duration)
}()
总结
Kratos中间件提供了强大而灵活的请求拦截机制,通过本文介绍的实现模板和注册方式,你可以轻松扩展各种横切功能。核心要点:
- 遵循
Middleware(Handler) Handler函数签名 - 使用
Chain组合多个中间件,注意执行顺序 - 根据需求选择全局、路由或应用级注册
- 优先使用异步处理避免影响主流程
中间件源码位于middleware/目录,包含认证、限流、追踪等丰富实现,建议深入阅读学习。通过合理使用中间件,可以显著提升代码复用率和系统可维护性。
Kratos中间件设计遵循"关注点分离"原则,让业务逻辑与通用功能解耦,是构建云原生微服务的关键技术之一。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考




