This is a creation in Article, where the information may have evolved or changed.
Grpc-go increases the functionality of the Interceptor (Interceptor), which, like the filter in the Java servlet, intercepts requests and responses to RPC, and can intercept both the client and the server.
With interceptors, GRPC can be extended, leveraging the power of the community to grow GRPC, or enable developers to handle business logic in GRPC processes with greater flexibility. Some of the functional frameworks implemented with interceptors are listed below:
- Go GRPC Middleware: Provides the interceptor chain function of interceptors, which can combine multiple interceptors into one interceptor chain, and of course it provides other functions, so it is named after the GRPC middleware.
- Grpc-multi-interceptor: is another interceptor chain function library, can also be a one-way or flow-type interceptor combination.
- Grpc_auth: Authentication Blocker
- Grpc_ctxtags: Adding a Map object to the context
Tag
- Grpc_zap: Support
zap
Log Framework
- Grpc_logrus: Support
logrus
Log Framework
- Grpc_prometheus: Support
prometheus
- OTGRPC: Support Opentracing/zipkin
- Grpc_opentracing: Support Opentracing/zipkin
- Grpc_retry: Adding retry functionality to the client
- Grpc_validator: The ability to add checksums to the server side
- Xrequestid: Set the request ID to the context
- Go-grpc-interceptor: Parsing
Accept-Language
and setting to context
- Requestdump: Output Request/response
There are also some other articles that describe the use of interceptors, such as the following two articles:
Introduction to OAuth on GRPC, Grpc Practice Interceptor Interceptor
I believe there will be more interesting interceptors to be contributed.
Note that the server can only configure a unary interceptor and stream interceptor, otherwise it will error, the client is also, although no error, but only the last one to work. If you want to configure multiple, you can use the aforementioned interceptor chain or implement one yourself.
Do you want to implement the Interceptor trouble? No trouble at all, on the contrary, very simple.
For a one-way invocation of the server-side interceptor, simply define a UnaryServerInterceptor
method:
1 |
type func Interface Interface {}, err Error) |
For interceptors called by server-side stream, just define a StreamServerInterceptor
method:
1 |
type func Interface {}, SS Serverstream, info *streamserverinfo, handler Streamhandler) error |
The parameters of the method include the context, the request and the stream, and the information to invoke the object.
For a one-way interception of the client, simply define a ' method:
1 |
type func string Interface {}, CC *clientconn, Invoker unaryinvoker, opts ... Calloption) Error |
For interception of the client stream, simply define a ' method:
1 |
type func string, Streamer streamer, opts ... Calloption) (Clientstream, error) |
You can see the implementation of some of the above-mentioned open-source interceptors, their implementation is not too complex, below we take a simple example of distance, before and after the method call to print a log.
Server-side Interceptors
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455 |
PackageMainImport("Log""NET""Flag"Pb"GITHUB.COM/SMALLNEST/GRPC/A/PB""Golang.org/x/net/context""Google.golang.org/grpc""Google.golang.org/grpc/reflection")var(port = flag.) String ("P",": 8972","Port"))typeServerstruct{}func(S *server) SayHello (CTX context. Context, in *PB. Hellorequest) (*PB. Helloreply, error) {return&PB. Helloreply{message:"Hello"+ In. Name},Nil}funcMain () {flag. Parse () lis, err: = Net. Listen ("TCP", *port)ifErr! =Nil{log. Fatalf ("Failed to listen:%v", err)}s: = Grpc. NewServer (GRPC. Streaminterceptor (Streamserverinterceptor), Grpc. Unaryinterceptor (Unaryserverinterceptor)) PB. Registergreeterserver (S, &server{}) reflection. Register (s)ifERR: = S.serve (LIS); Err! =Nil{log. Fatalf ("Failed to serve:%v", err)}}funcUnaryserverinterceptor (CTX context. Context, reqInterface{}, Info *grpc. Unaryserverinfo, Handler Grpc. Unaryhandler) (Interface{}, error) {log. Printf ("before handling. Info:%+v ", info) resp, err: = Handler (CTX, req) log. Printf ("after handling." RESP:%+v ", resp)returnRESP, err}//Streamserverinterceptor is a GRPC server-side interceptor, provides Prometheus monitoring for streaming RPCs.
funcStreamserverinterceptor (SRVInterface{}, SS Grpc. Serverstream, Info *grpc. Streamserverinfo, Handler Grpc. Streamhandler) Error {log. Printf ("before handling. Info:%+v ", info) Err: = Handler (SRV, ss) log. Printf ("after handling." ERR:%v ", err)returnErr |
grpc.NewServer
The interceptor can be passed in as a parameter, and when the service is provided, we can see that the interceptor prints the log:
12 |
./Geneva/ - at: the: -Before handling.Info:&{Server:0x17309c8 Fullmethod:/PB.Greeter/SayHello} ./Geneva/ - at: the: -After handling.resp:&helloreply{Message: HelloWorld,} |
Blocker for clients
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152 |
PackageMainImport(//"context""Flag""Log""Golang.org/x/net/context"Pb"GITHUB.COM/SMALLNEST/GRPC/A/PB""Google.golang.org/grpc")var(address = flag.) String ("Addr","localhost:8972","Address") name = flag. String ("n","World","Name"))funcMain () {flag. Parse ()//Connection ServerConn, err: = Grpc. Dial (*address, Grpc. Withinsecure (), Grpc. Withunaryinterceptor (Unaryclientinterceptor), Grpc. Withstreaminterceptor (Streamclientinterceptor))ifErr! =Nil{log. Fatalf ("faild to connect:%v", err)}deferConn. Close () c: = PB. Newgreeterclient (conn) R, Err: = C.sayhello (context. Background (), &PB. Hellorequest{name: *name})ifErr! =Nil{log. Fatalf ("Could not greet:%v", err)}log. Printf ("Greeting:%s", R.message)}funcUnaryclientinterceptor (CTX context. Context, methodstring, req, replyInterface{}, CC *grpc. Clientconn, Invoker Grpc. Unaryinvoker, opts ... grpc. Calloption) Error {log. Printf ("before Invoker. Method:%+v, Request:%+v ", method, req) Err: = Invoker (CTx, method, req, reply, CC, opts ...) Log. Printf ("after Invoker." Reply:%+v ", reply)returnErrfuncStreamclientinterceptor (CTX context. Context, desc *grpc. Streamdesc, CC *GRPC. Clientconn, methodstring, Streamer Grpc. Streamer, opts ... grpc. calloption) (Grpc. Clientstream, error) {log. Printf ("before Invoker. Method:%+v, Streamdesc:%+v ", method, desc) Clientstream, err: = Streamer (CTX, DESC, cc, method, opts ...) Log. Printf ("before Invoker. Method:%+v ", method)returnClientstream, err} |
Through grpc.WithUnaryInterceptor
, grpc.WithStreamInterceptor
you can pass the interceptor to Dial
do parameters. When the client calls, you can view the log of the Interceptor output:
123 |
2017/04 /17 23 : 34 : 20 before invoker. method : /pb. Greeter/sayhello, Request:&hellorequest{name:world,} 2017 /04 /17 23 : 34 : 20 after invoker. Reply: &helloreply{message:hello World,} 2017 /04 /17 23 : 34 : 20 Greeting:hello World |
With this simple example, you can easily understand the development of interceptors. Unary and stream two types of interceptors can be implemented differently depending on your grpc server/client implementation.