Kratos 中間件-概覽

2022-04-25 10:01 更新

概覽

Kratos 內(nèi)置了一系列的 middleware(中間件)用于處理 logging、 metrics 等通用場景。您也可以通過實現(xiàn) Middleware 接口,開發(fā)自定義 middleware,進行通用的業(yè)務處理,比如用戶登錄鑒權等。

內(nèi)置中間件

相關代碼均可以在?middleware?目錄下找到。

  • logging: 用于請求日志的記錄。
  • metrics: 用于啟用metric。
  • recovery: 用于recovery panic。
  • tracing: 用于啟用trace。
  • validate: 用于處理參數(shù)校驗。
  • metadata: 用于啟用元信息傳遞
  • auth: 用于提供基于JWT的認證請求
  • ratelimit: 用于服務端流量限制
  • circuitbreaker: 用于客戶端熔斷控制

生效順序

一個請求進入時的處理順序為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)
        }
    }
}

定制中間件

對特定路由定制中間件

  • server:?selector.Server(ms...) ?
  • client:?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?

http server

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(),
        )

http client

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(),
        )

grpc server

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(),
        )

grpc client

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

operation查找

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;
}


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號