Skip to main content

概览

Kratos 内置了一系列的 middleware(中间件)用于处理 logging、 metrics 等通用场景。您也可以通过实现 Middleware 接口,开发自定义 middleware,进行通用的业务处理,比如用户登录鉴权等。

内置中间件#

相关代码均可以在middleware目录下找到。

  • logging: 用于请求日志的记录。
  • metrics: 用于启用metric。
  • recovery: 用于recovery panic。
  • tracing: 用于启用trace。
  • validate: 用于处理参数校验。
  • metadata: 用于启用元信息传递

生效顺序#

一个请求进入时的处理顺序为Middleware注册的顺序,而响应返回的处理顺序为注册顺序的倒序。

         ┌───────────────────┐         │MIDDLEWARE 1       │         │ ┌────────────────┐│         │ │MIDDLEWARE 2    ││         │ │ ┌─────────────┐││         │ │ │MIDDLEWARE 3 │││         │ │ │ ┌─────────┐ │││REQUEST  │ │ │ │  YOUR   │ │││  RESPONSE   ──────┼─┼─┼─▷ HANDLER ○─┼┼┼───▷         │ │ │ └─────────┘ │││         │ │ └─────────────┘││         │ └────────────────┘│         └───────────────────┘

使用中间件#

NewGRPCServerNewHTTPServer中通过ServerOption进行注册。 如

// http// 定义optsvar opts = []http.ServerOption{    http.Middleware(        recovery.Recovery(), // 把middleware按照需要的顺序加入        tracing.Server(),        logging.Server(),    ),}// 创建serverhttp.NewServer(opts...)


//grpcvar opts = []grpc.ServerOption{    grpc.Middleware(        recovery.Recovery(),  // 把middleware按照需要的顺序加入        tracing.Server(),        logging.Server(),    ),}// 创建servergrpc.NewServer(opts...)

自定义中间件#

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

基本的代码模板

import (    "context"
    "github.com/go-kratos/kratos/v2/middleware"    "github.com/go-kratos/kratos/v2/transport")
func Middleware1() 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 {                // Do something on entering                 defer func() {                 // Do something on exiting                 }()            }            return handler(ctx, req)        }    }}

定制中间件#

对特定路由定制中间件

  • server:selector.Server(ms...)
  • client:selector.Client(ms...)

匹配规则(多参数)

  • Path(path...) 路由匹配
  • Regex(regex...) 正则匹配
  • Prefix(prefix...) 前缀匹配
  • Match(fn) 函数匹配,函数格式为func(operation string) bool,operation为path,函数返回值为true,匹配成功

http server

http.Middleware(            selector.Server(recovery.Recovery(), tracing.Server(),testMiddleware).                Path("/hello.Update/UpdateUser", "/hello.kratos/SayHello").                Regex(`/test.hello/Get[0-9]+`).                Prefix("/kratos.", "/go-kratos.", "/helloworld.Greeter/").                Build(),        )

http client

http.WithMiddleware(            selector.Client(recovery.Recovery(), tracing.Server(),testMiddleware).                Path("/hello.Update/UpdateUser", "/hello.kratos/SayHello").                Regex(`/test.hello/Get[0-9]+`).                Prefix("/kratos.", "/go-kratos.", "/helloworld.Greeter/").                Match(func(operation string) bool {                    if strings.HasPrefix(operation, "/go-kratos.dev") || strings.HasSuffix(operation, "world") {                        return true                    }                    return false                }).Build(),        )

grpc server

grpc.Middleware(            selector.Server(recovery.Recovery(), tracing.Server(),testMiddleware).                Path("/hello.Update/UpdateUser", "/hello.kratos/SayHello").                Regex(`/test.hello/Get[0-9]+`).                Prefix("/kratos.", "/go-kratos.", "/helloworld.Greeter/").                Build(),        )

grpc client

grpc.Middleware(            selector.Client(recovery.Recovery(), tracing.Server(),testMiddleware).                Path("/hello.Update/UpdateUser", "/hello.kratos/SayHello").                Regex(`/test.hello/Get[0-9]+`).                Prefix("/kratos.", "/go-kratos.", "/helloworld.Greeter/").                Build(),        )

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

operation 是 HTTP 及 gRPC 统一的 gRPC path

operation查找

gRPC path 的拼接规则为 /包名.服务名/方法名

比如在如下 proto 文件中,我们要调用 SayHello 这个方法,那么 operation 就为 /helloworld.Greeter/SayHello

syntax = "proto3";
package helloworld;
import "google/api/annotations.proto";
option go_package = "github.com/go-kratos/kratos/examples/helloworld/helloworld";
// The greeting service definition.service Greeter {  // Sends a greeting  rpc SayHello (HelloRequest) returns (HelloReply)  {        option (google.api.http) = {            get: "/helloworld/{name}",        };  }}// The request message containing the user's name.message HelloRequest {  string name = 1;}
// The response message containing the greetingsmessage HelloReply {  string message = 1;}