gRPC- interceptor simple to use

Outline

As a general gRPC RPC framework built interceptor function. Including server-side and client-side interceptor interceptors, similar use. The main role is to perform additional processing before or after rpc call.

From the client perspective, before the request may be initiated, intercept and modify parameters of the request; response parameters can also modify the server.

Examples

The following write a simple example to describe the specific functions implemented. Go to language, for example, other languages ​​gRPC library should also have similar features, please refer to specific documentation.

For a simple example, it simplifies the handling of the error. And only shows part of the code, please refer to the complete project GitHub repository pnnh / suji-go

Interface description

syntax = "proto3";

package suji;

service Suji {
    rpc Say(SayRequest) returns (SayReply) {}
}

message SayRequest {
    string msg = 1;
}

message SayReply {
    string msg = 1;
}

Initial implementation

Server main method

func main() {
    lis, err := net.Listen("tcp", "0.0.0.0:1301")
    if err != nil {
        log.Fatalln("监听出错", err)
        return
    }

    grpcServer := grpc.NewServer()
    suji.RegisterSujiServer(grpcServer, &server.SujiServer{})

    if err = grpcServer.Serve(lis); err != nil {
        log.Fatalln("服务停止", err)
    }
}

Client main method

func main() {
    addr := "127.0.0.1:1301"
    c := client.LinkSujiServer(addr)
    
    rep := client.Say(c, msg)
    log.Println("收到:", rep.Msg)
}

Here are connected by the method to gRPC LinkSujiServer server, calls the interface Say, and the print server returns the value.

LinkSujiServer follows

func LinkSujiServer(target string) suji.SujiClient {
    conn, err := grpc.DialContext(context.Background(), target, grpc.WithInsecure())
    if err != nil {
        log.Fatalln("链接至服务出错", err, target)
    }
    return suji.NewSujiClient(conn)
}

Say Interface client calls as follows:


func Say(client suji.SujiClient, msg string) *suji.SayReply {
    request := &suji.SayRequest{Msg: msg}

    reply, err := client.Say(context.Background(), request)
    if err != nil {
        log.Fatalln("调用出错", err)
    }
    return reply
}

Say Interface server to achieve the following content will be received as it is returned to the caller:

func (s *SujiServer) Say(ctx context.Context, req *suji.SayRequest) (*suji.SayReply, error) {
    log.Println("收到:", req.Msg)

    reply := &suji.SayReply{Msg: req.Msg}

    return reply, nil
}

Running this code will print the following results were

Client:

2019/08/15 18:19:59 发送: 你好
2019/08/15 18:19:59 收到: 你好

server:

2019/08/15 18:19:59 收到: 你好
2019/08/15 18:19:59 回复: 你好

Interceptor achieve

We had a very simple interface calls, and now we pass gRPC client interceptors to add new points to this conversation.

We will interceptor to intercept and tamper with the content sent by the client to the server, then the content returned by the server also tampered out. All this is done quietly in the interceptor, the call originator and the recipient does not know.

Define interceptor methods

func callInterceptor(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn,
    invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {

    if reqParam, ok := req.(*suji.SayRequest); ok {
        newMsg := strings.Replace(reqParam.Msg, "喜欢", "讨厌", 1)
        req = &suji.SayRequest{Msg: newMsg}
    }

    err := invoker(ctx, method, req, reply, cc, opts...)
    if err != nil {
        log.Println("接口调用出错", method, err)
        return err
    }

    if replyParam, ok := reply.(*suji.SayReply); ok {
        newMsg := strings.Replace(replyParam.Msg, "讨厌", "喜欢", 1)
        replyParam.Msg = newMsg
    }

    return nil
}

The method explained later, here to modify the method of connection to the server, adding interceptors options:


func LinkSujiServer(target string) suji.SujiClient {
    conn, err := grpc.DialContext(context.Background(), target, grpc.WithInsecure(),
        grpc.WithUnaryInterceptor(callInterceptor))
    if err != nil {
        log.Fatalln("链接至服务出错", err, target)
    }
    return suji.NewSujiClient(conn)
}

Note that the new grpc.WithUnaryInterceptor (callInterceptor) this line.

It will be passed in several useful parameters for our defined callInterceptor gRPC runtime. Wherein the method is call interface path, req respectively corresponding reply and request interface and output parameters. The invoker argument is a method for performing the original RPC request, if you call this method, the RPC request will not be sent to the server.

Here, we, and the parameter is determined by tampering request and response type. Meanwhile, in order to make more interesting example, a simple modification of the main function code.

Client main method

func main() {
    addr := "127.0.0.1:1301"

    c := client.LinkSujiServer(addr)

    msg := "我喜欢你"
    log.Println("发送:", msg)
    rep := client.Say(c, msg)

    log.Println("收到:", rep.Msg)

    if strings.Contains(rep.Msg, "喜欢") {
        log.Println("内心:", "好开心啊")
    }
}

Say server method

func (s *SujiServer) Say(ctx context.Context, req *suji.SayRequest) (*suji.SayReply, error) {
    log.Println("收到:", req.Msg)

    reply := &suji.SayReply{}
    if strings.Contains(req.Msg, "讨厌") {
        reply.Msg = "我也讨厌你"
    }
    log.Println("回复:", reply.Msg)
    log.Println("内心:", "沙雕")

    return reply, nil
}

Look at the inner sides of the lower output feelings under it:

Client output:

2019/08/15 19:07:14 发送: 我喜欢你
2019/08/15 19:07:14 收到: 我也喜欢你
2019/08/15 19:07:14 内心: 好开心啊

Server output:

2019/08/15 19:07:14 收到: 我讨厌你
2019/08/15 19:07:14 回复: 我也讨厌你
2019/08/15 19:07:14 内心: 沙雕

At last

In addition to one yuan gRPC interceptor also provides a method of setting the flow interceptor, provided a connection is established through grpc.WithStreamInterceptor method. With monohydric flow interceptor interceptor function is substantially the same, the specific application may reference library related documentation or source code.

Guess you like

Origin www.cnblogs.com/coloc/p/11360071.html