【go】【grpc】【interceptor】

Nones發表於2024-06-15

@

目錄
  • 寫在前面
    • 客戶端 unary interceptor
    • 伺服器 nuary interceptor
    • 客戶端 stream interceptor
    • 伺服器 stream interceptor
    • 伺服器 多 unay interceptor
  • 具體例子
    • 伺服器 unary interceptor
    • 多攔截器
  • 參考資料
    • 基礎/標準庫/第三方庫
    • golang 導航
    • 程式設計規範
    • 演算法|面試
    • 專案


寫在前面

  • 相關博文
  • 個人部落格首頁
  • 免責宣告:僅供學習交流使用!開源框架可能存在的風險和相關後果將完全由使用者自行承擔,本人不承擔任何法律責任。

客戶端 unary interceptor

import (
    "context"
    "fmt"
    "google.golang.org/grpc"
    pb "path/to/your/protobuf/package"
)

// 客戶端一元攔截器函式
func clientUnaryInterceptor(
    ctx context.Context,
    method string,
    req, reply interface{},
    cc *grpc.ClientConn,
    invoker grpc.UnaryInvoker,
    opts ...grpc.CallOption,
) error {
    // 在請求之前處理
    fmt.Println("Before RPC call:", method)
    
    // 呼叫實際的RPC方法
    err := invoker(ctx, method, req, reply, cc, opts...)
    
    // 在響應之後處理
    fmt.Println("After RPC call:", method)
    
    return err
}

func main() {
    // 建立一個帶有攔截器的連線
    conn, err := grpc.Dial(
        "localhost:50051",
        grpc.WithInsecure(),
        grpc.WithUnaryInterceptor(clientUnaryInterceptor),
    )
    if err != nil {
        fmt.Println("Failed to connect:", err)
        return
    }
    defer conn.Close()

    // 建立客戶端存根
    client := pb.NewYourServiceClient(conn)

    // 呼叫服務方法
    resp, err := client.YourMethod(context.Background(), &pb.YourRequest{})
    if err != nil {
        fmt.Println("Error calling service:", err)
        return
    }

    fmt.Println("Response from service:", resp)
}

伺服器 nuary interceptor

import (
    "context"
    "fmt"
    "google.golang.org/grpc"
    "net"
    pb "path/to/your/protobuf/package"
)

// 伺服器端一元攔截器函式
func serverUnaryInterceptor(
    ctx context.Context,
    req interface{},
    info *grpc.UnaryServerInfo,
    handler grpc.UnaryHandler,
) (interface{}, error) {
    // 在請求處理之前處理
    fmt.Println("Before handling RPC call:", info.FullMethod)
    
    // 呼叫實際的服務方法
    resp, err := handler(ctx, req)
    
    // 在響應之後處理
    fmt.Println("After handling RPC call:", info.FullMethod)
    
    return resp, err
}

type server struct {
    pb.UnimplementedYourServiceServer
}

func (s *server) YourMethod(ctx context.Context, req *pb.YourRequest) (*pb.YourResponse, error) {
    // 服務邏輯
    return &pb.YourResponse{}, nil
}

func main() {
    // 建立一個gRPC伺服器並新增一元攔截器
    grpcServer := grpc.NewServer(grpc.UnaryInterceptor(serverUnaryInterceptor))
    pb.RegisterYourServiceServer(grpcServer, &server{})

    // 啟動伺服器
    lis, err := net.Listen("tcp", ":50051")
    if err != nil {
        fmt.Println("Failed to listen:", err)
        return
    }
    if err := grpcServer.Serve(lis); err != nil {
        fmt.Println("Failed to serve:", err)
        return
    }
}

客戶端 stream interceptor

import (
    "context"
    "fmt"
    "google.golang.org/grpc"
    pb "path/to/your/protobuf/package"
)

// 客戶端流式攔截器函式
func clientStreamInterceptor(
    ctx context.Context,
    desc *grpc.StreamDesc,
    cc *grpc.ClientConn,
    method string,
    streamer grpc.Streamer,
    opts ...grpc.CallOption,
) (grpc.ClientStream, error) {
    // 在請求之前處理
    fmt.Println("Before streaming RPC call:", method)
    
    // 呼叫實際的流式RPC方法
    clientStream, err := streamer(ctx, desc, cc, method, opts...)
    
    // 在響應之後處理
    fmt.Println("After streaming RPC call:", method)
    
    return clientStream, err
}

func main() {
    // 建立一個帶有攔截器的連線
    conn, err := grpc.Dial(
        "localhost:50051",
        grpc.WithInsecure(),
        grpc.WithStreamInterceptor(clientStreamInterceptor),
    )
    if err != nil {
        fmt.Println("Failed to connect:", err)
        return
    }
    defer conn.Close()

    // 建立客戶端存根
    client := pb.NewYourServiceClient(conn)

    // 呼叫服務方法
    stream, err := client.YourStreamingMethod(context.Background())
    if err != nil {
        fmt.Println("Error calling service:", err)
        return
    }

    // 處理流資料
    for {
        resp, err := stream.Recv()
        if err != nil {
            if err == io.EOF {
                break
            }
            fmt.Println("Error receiving stream:", err)
            return
        }
        fmt.Println("Received message from stream:", resp)
    }
}

伺服器 stream interceptor

import (
    "context"
    "fmt"
    "google.golang.org/grpc"
    "net"
    pb "path/to/your/protobuf/package"
)

// 伺服器端流式攔截器函式
func serverStreamInterceptor(
    srv interface{},
    ss grpc.ServerStream,
    info *grpc.StreamServerInfo,
    handler grpc.StreamHandler,
) error {
    // 在請求處理之前處理
    fmt.Println("Before handling streaming RPC call:", info.FullMethod)
    
    // 呼叫實際的流式RPC方法
    err := handler(srv, ss)
    
    // 在響應之後處理
    fmt.Println("After handling streaming RPC call:", info.FullMethod)
    
    return err
}

type server struct {
    pb.UnimplementedYourServiceServer
}

func (s *server) YourStreamingMethod(stream pb.YourService_YourStreamingMethodServer) error {
    // 服務邏輯
    return nil
}

func main() {
    // 建立一個gRPC伺服器並新增流式攔截器
    grpcServer := grpc.NewServer(grpc.StreamInterceptor(serverStreamInterceptor))
    pb.RegisterYourServiceServer(grpcServer, &server{})

    // 啟動伺服器
    lis, err := net.Listen("tcp", ":50051")
    if err != nil {
        fmt.Println("Failed to listen:", err)
        return
    }
    if err := grpcServer.Serve(lis); err != nil {
        fmt.Println("Failed to serve:", err)
        return
    }
}

伺服器 多 unay interceptor

import (
    "context"
    "fmt"
    "google.golang.org/grpc"
    "net"
    pb "path/to/your/protobuf/package"
)

// 第一個伺服器端一元攔截器
func firstServerUnaryInterceptor(
    ctx context.Context,
    req interface{},
    info *grpc.UnaryServerInfo,
    handler grpc.UnaryHandler,
) (interface{}, error) {
    fmt.Println("First unary interceptor - Before handling RPC call:", info.FullMethod)
    resp, err := handler(ctx, req)
    fmt.Println("First unary interceptor - After handling RPC call:", info.FullMethod)
    return resp, err
}

// 第二個伺服器端一元攔截器
func secondServerUnaryInterceptor(
    ctx context.Context,
    req interface{},
    info *grpc.UnaryServerInfo,
    handler grpc.UnaryHandler,
) (interface{}, error) {
    fmt.Println("Second unary interceptor - Before handling RPC call:", info.FullMethod)
    resp, err := handler(ctx, req)
    fmt.Println("Second unary interceptor - After handling RPC call:", info.FullMethod)
    return resp, err
}

type server struct {
    pb.UnimplementedYourServiceServer
}

func (s *server) YourMethod(ctx context.Context, req *pb.YourRequest) (*pb.YourResponse, error) {
    return &pb.YourResponse{}, nil
}

func main() {
    // 建立一個帶有多個攔截器的gRPC伺服器
    grpcServer := grpc.NewServer(
        grpc.ChainUnaryInterceptor(firstServerUnaryInterceptor, secondServerUnaryInterceptor),
    )
    pb.RegisterYourServiceServer(grpcServer, &server{})

    // 啟動伺服器
    lis, err := net.Listen("tcp", ":50051")
    if err != nil {
        fmt.Println("Failed to listen:", err)
        return
    }
    if err := grpcServer.Serve(lis); err != nil {
        fmt.Println("Failed to serve:", err)
        return
    }
}


具體例子

伺服器 unary interceptor

	"context"
	assetfs "github.com/elazarl/go-bindata-assetfs"
	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
	"golang.org/x/net/http2"
	"golang.org/x/net/http2/h2c"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/reflection"
	"log"
	"net/http"
	"path"
	"strings"
)
func handleRpc() *grpc.Server {
	//a := api.Api{Ctx: context.TODO(), Url: "http://localhost", Ak: "string", Sk: "string"}
	//list, err := a.TagList()
	//fmt.Printf("%#v,%s", list, err)
	tag := server.NewTag("http://localhost:8080", "string", "string")
	//res, err := tag.TagList()
	//if err != nil {
	//	return
	//}
	//fmt.Printf("%s,%s", res.String(), err)
	interceptors := []grpc.ServerOption{grpc.UnaryInterceptor(HelloInterceptor)}
	svc := grpc.NewServer(interceptors...)
	proto.RegisterTagSvcServer(svc, tag)
	reflection.Register(svc)
	return svc
}
func handleGrpcGateway(port string) *runtime.ServeMux {
	endpoint := "0.0.0.0:" + port
	g := runtime.NewServeMux()
	dopts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
	_ = proto.RegisterTagSvcHandlerFromEndpoint(context.Background(), g, endpoint, dopts)

	return g
}

func HelloInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
	log.Println("你好")
	resp, err := handler(ctx, req)
	log.Println("再見")
	return resp, err
}


多攔截器

func handleRpc() *grpc.Server {
	//a := api.Api{Ctx: context.TODO(), Url: "http://localhost", Ak: "string", Sk: "string"}
	//list, err := a.TagList()
	//fmt.Printf("%#v,%s", list, err)
	tag := server.NewTag("http://localhost:8080", "string", "string")
	//res, err := tag.TagList()
	//if err != nil {
	//	return
	//}
	//fmt.Printf("%s,%s", res.String(), err)
	interceptors := grpc.ChainUnaryInterceptor(HelloInterceptor, WorldInterceptor)
	svc := grpc.NewServer(interceptors)
	proto.RegisterTagSvcServer(svc, tag)
	reflection.Register(svc)
	return svc
}
func handleGrpcGateway(port string) *runtime.ServeMux {
	endpoint := "0.0.0.0:" + port
	g := runtime.NewServeMux()
	dopts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
	_ = proto.RegisterTagSvcHandlerFromEndpoint(context.Background(), g, endpoint, dopts)

	return g
}

func HelloInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
	log.Println("你好")
	resp, err := handler(ctx, req)
	log.Println("再見")
	return resp, err
}
func WorldInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
	log.Println("你好")
	resp, err := handler(ctx, req)
	log.Println("再見")
	return resp, err
}


參考資料

基礎/標準庫/第三方庫


  • 地鼠文件:比較多資料
  • topgoer
  • go awesome
  • golang 文件學習
  • golang 標準庫
  • go 檔案常用操作

golang 導航


  • golang 收集
  • go-guide
  • golang 導航
  • go-concurrency-guide
  • go-advice
  • golang 知識路線

程式設計規範


  • golang 程式設計規範
  • golang 規範示例

演算法|面試


  • cs 面試
  • 面試網站
  • Golang後端研發崗位相關面試題和簡歷
  • 路人張的面試筆記
  • golang 演算法

專案


  • golang 專案推薦
  • 7天系列
  • go專案推薦
  • go高效能程式設計

相關文章