Kratos 內(nèi)置了一系列的 middleware(中間件)用于處理 logging、 metrics 等通用場景。您也可以通過實現(xiàn) Middleware 接口,開發(fā)自定義 middleware,進行通用的業(yè)務處理,比如用戶登錄鑒權等。
相關代碼均可以在?middleware
?目錄下找到。
一個請求進入時的處理順序為Middleware注冊的順序,而響應返回的處理順序為注冊順序的倒序。
┌───────────────────┐
│MIDDLEWARE 1 │
│ ┌────────────────┐│
│ │MIDDLEWARE 2 ││
│ │ ┌─────────────┐││
│ │ │MIDDLEWARE 3 │││
│ │ │ ┌─────────┐ │││
REQUEST │ │ │ │ YOUR │ │││ RESPONSE
──────┼─┼─┼─? HANDLER ○─┼┼┼───?
│ │ │ └─────────┘ │││
│ │ └─────────────┘││
│ └────────────────┘│
└───────────────────┘
在?NewGRPCServer
?和?NewHTTPServer
?中通過?ServerOption
?進行注冊。 如
// http
// 定義opts
var opts = []http.ServerOption{
http.Middleware(
recovery.Recovery(), // 把middleware按照需要的順序加入
tracing.Server(),
logging.Server(),
),
}
// 創(chuàng)建server
http.NewServer(opts...)
//grpc
var opts = []grpc.ServerOption{
grpc.Middleware(
recovery.Recovery(), // 把middleware按照需要的順序加入
tracing.Server(),
logging.Server(),
),
}
// 創(chuàng)建server
grpc.NewServer(opts...)
需要實現(xiàn)?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)
}
}
}
對特定路由定制中間件
selector.Server(ms...)
?selector.Client(ms...)
?匹配規(guī)則(多參數(shù))
Path(path...)
? 路由匹配
Regex(regex...)
?正則匹配
Prefix(prefix...)
? 前綴匹配
Match(fn)
? 函數(shù)匹配,函數(shù)格式為?func(ctx context.Context,operation string) bool
?,?operation
?為path,函數(shù)返回值為?true
?,匹配成功, ?ctx
?可使用?transport.FromServerContext(ctx)
? 或者?transport.FromClientContext(ctx)
?獲取 ?Transporter
?import "github.com/go-kratos/kratos/v2/middleware/selector"
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(),
)
import "github.com/go-kratos/kratos/v2/middleware/selector"
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(ctx context.Context,operation string) bool {
if strings.HasPrefix(operation, "/go-kratos.dev") || strings.HasSuffix(operation, "world") {
return true
}
tr, ok := transport.FromClientContext(ctx)
if !ok {
return false
}
if tr.RequestHeader().Get("go-kratos") == "kratos" {
return true
}
return false
}).Build(),
)
import "github.com/go-kratos/kratos/v2/middleware/selector"
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(),
)
import "github.com/go-kratos/kratos/v2/middleware/selector"
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本身的路由!?。?br> operation 是 HTTP 及 gRPC 統(tǒng)一的 gRPC path
gRPC path 的拼接規(guī)則為 ?/包名.服務名/方法名
?
比如在如下 proto 文件中,我們要調(diào)用 SayHello 這個方法,那么 operation 就為 ?/helloworld.Greeter/SayHello
?
syntax = "proto3";
package helloworld;
import "google/api/annotations.proto";
option go_package = "github.com/go-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 greetings
message HelloReply {
string message = 1;
}
更多建議: