gRPC中interceptor攔截器的使用教程
一、使用場景
gRPC中的interceptor攔截器分為客戶端攔截器和服務(wù)端攔截器,分別是在客戶端和服務(wù)端的請求被發(fā)送出去之前進行處理的邏輯。常見的使用場景有:(1)請求日志記錄及監(jiān)控;(2)添加請求頭數(shù)據(jù)、以便代理轉(zhuǎn)發(fā)使用;(3)請求或者結(jié)果重寫。
二、原理分析
1.interceptor介紹
攔截器是調(diào)用在還沒有到達目的地之前進行處理的邏輯,類似于Spring框架中存在的Interceptor。
gRPC 攔截器主要分為兩種:客戶端攔截器(ClientInterceptor),服務(wù)端攔截器(ServerInterceptor),顧名思義,分別于請求的兩端執(zhí)行相應(yīng)的前攔截處理。
2.使用方法說明
2.1.ClientInterceptor 源碼
@ThreadSafe public interface ClientInterceptor { ? <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall( ? ? ? MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next); }
它只有一個方法:interceptCall,對于注冊了相應(yīng)攔截器的客戶端調(diào)用,都要經(jīng)過這個方法。
參數(shù):
1、method:MethodDescriptor 類型,標示請求方法。包括方法全限定名稱、請求服務(wù)名稱、請求、結(jié)果、序列化工具、冪等等。
2、callOptions:此次請求的附帶信息。
3、next:執(zhí)行此次 RPC 請求的抽象鏈接管道(Channel)
返回:
ClientCall,包含請求及結(jié)果信息,并且不為null。
2.2.ServerInterceptor 源碼
@ThreadSafe public interface ServerInterceptor { ? <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall( ? ? ? ServerCall<ReqT, RespT> call, ? ? ? Metadata headers, ? ? ? ServerCallHandler<ReqT, RespT> next); }
它只有一個方法:interceptCall,對于注冊了相應(yīng)攔截器的服務(wù)端調(diào)用,都要經(jīng)過這個方法。
參數(shù):
- call:ServerCall 對象,包含客戶端請求的 MethodDescriptor
- headers:請求頭信息
- next:處理鏈條上的下一個處理。
三、代碼實踐
1.實現(xiàn)功能
通過代碼實現(xiàn)以下功能:
- 使用grpc打印日志;
- 獲取header信息,返回header信息;
- 使用grpc獲取ip信息,獲取客戶端傳遞過來的信息;
2.服務(wù)端實現(xiàn)代碼
(1)實現(xiàn)自定義ServerGrpcInterceptor
只需要實現(xiàn)ServerInterceptor接口,只需要重寫interceptCall方法
import io.grpc.*; import io.grpc.netty.shaded.io.netty.util.internal.StringUtil; import lombok.extern.slf4j.Slf4j; import java.util.HashMap; import java.util.Map; /** * @author yangnk * @desc * @date 2023/08/07 23:17 **/ @Slf4j public class MyServerGrpcInterceptor implements ServerInterceptor { ??? @Override ??? public? ServerCall.Listener interceptCall(ServerCall serverCall, Metadata metadata, ServerCallHandler serverCallHandler) { ??????? //1.打印請求方法 ??????? log.info("請求方法:{}", serverCall.getMethodDescriptor()); ??????? //2.從請求的屬性中獲取遠程地址 ??????? String remoteAddr = serverCall.getAttributes().get(Grpc.TRANSPORT_ATTR_REMOTE_ADDR).toString(); ??????? log.info("遠程地址為:{}", remoteAddr); ??????? //3.獲取header中的參數(shù)進行業(yè)務(wù)處理 ??????? Map map = new HashMap(); ??????? map.put("00000001", "admin"); ??????? //獲取header中參數(shù) ??????? Metadata.Key token = Metadata.Key.of("token", Metadata.ASCII_STRING_MARSHALLER); ??????? Metadata.Key userId = Metadata.Key.of("userId", Metadata.ASCII_STRING_MARSHALLER); ??????? String tokenStr = metadata.get(token); ??????? if (StringUtil.isNullOrEmpty(tokenStr)){ ??????????? System.err.println("未收到客戶端token,關(guān)閉此連接"); ??????????? serverCall.close(Status.DATA_LOSS,metadata); ??????? } ??????? //獲得token去中查詢 ??????? String userInfo = map.get(metadata.get(userId)); ??????? if(StringUtil.isNullOrEmpty(userInfo)){ ??????????? System.err.println("客戶端token錯誤,關(guān)閉此連接"); ??????????? serverCall.close(Status.DATA_LOSS,metadata); ??????? } ??????? //服務(wù)端寫回參數(shù) ??????? ServerCall newServerCall = new ForwardingServerCall.SimpleForwardingServerCall(serverCall) { ??????????? @Override ??????????? public void sendHeaders(Metadata headers) { ??????????????? headers.put(userId,userInfo); ??????????????? super.sendHeaders(headers); ??????????? } ??????? }; ??????? return serverCallHandler.startCall(newServerCall, metadata); ??? } }
(2)全局配置ServerGrpcInterceptor
通過@GrpcGlobalServerInterceptor注解配置Interceptor
import com.yangnk.grpcserver.dialoutService.DialoutGrpcInterceptor; import com.yangnk.grpcserver.dialoutService.MyServerGrpcInterceptor; import io.grpc.ServerInterceptor; import net.devh.boot.grpc.server.interceptor.GrpcGlobalServerInterceptor; import org.springframework.context.annotation.Configuration; @Configuration(proxyBeanMethods = false) public class GlobalInterceptorConfiguration { ??? @GrpcGlobalServerInterceptor ??? ServerInterceptor myServerInterceptor() { ??????? return new MyServerGrpcInterceptor(); ??? } }
3.客戶端實現(xiàn)代碼
(1)實現(xiàn)自定義ClientGrpcInterceptor
只需要實現(xiàn)ClientInterceptor接口,只需要重寫interceptCall方法
import io.grpc.*; import lombok.extern.slf4j.Slf4j; /** * @author yangnk * @desc * @date 2023/08/08 00:15 **/ @Slf4j public class MyClientGrpcInterceptor implements ClientInterceptor { ??? @Override ??? public? ClientCall interceptCall(MethodDescriptor method, CallOptions callOptions, Channel next) { ??????? Metadata.Key token = Metadata.Key.of("token", Metadata.ASCII_STRING_MARSHALLER); ??????? Metadata.Key userId = Metadata.Key.of("userId", Metadata.ASCII_STRING_MARSHALLER); ??????? //1.打印日志 ??????? log.info("請求名稱:{}", method.getFullMethodName()); ??????? //2.請求參數(shù)放到header中 ??????? return new ForwardingClientCall.SimpleForwardingClientCall(next.newCall(method, callOptions)) { ??????????? @Override ??????????? public void start(Listener responseListener, Metadata headers) { ??????????????? //此處為你登錄后獲得的token的值 ??????????????? headers.put(userId, "00000001"); ??????????????? headers.put(token, "A2D05E5ED2414B1F8C6AEB19F40EF77C"); ??????????????? super.start(new ForwardingClientCallListener.SimpleForwardingClientCallListener(responseListener) { ??????????????????? @Override ??????????????????? public void onHeaders(Metadata headers) { ??????????????????????? log.info("請求返回信息為:" + headers); ??????????????????????? super.onHeaders(headers); ??????????????????? } ??????????????? }, headers); ??????????? } ??????? }; ??? } }
(2)全局配置ClientGrpcInterceptor
通過@GrpcGlobalClientInterceptor注解配置Interceptor
import io.grpc.ClientInterceptor; import net.devh.boot.grpc.client.interceptor.GrpcGlobalClientInterceptor; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; @Order(Ordered.LOWEST_PRECEDENCE) @Configuration(proxyBeanMethods = false) public class GlobalClientInterceptorConfiguration { ??? @GrpcGlobalClientInterceptor ??? ClientInterceptor myClientInterceptor() { ??????? return new MyClientGrpcInterceptor(); ??? } }
4.驗證結(jié)果
服務(wù)端請求結(jié)果:
客戶端請求結(jié)果:
代碼地址:https://github.com/yangnk/SpringBoot_Learning/tree/master/GRPCDemo
以上就是gRPC中interceptor攔截器的使用教程的詳細內(nèi)容,更多關(guān)于interceptor攔截器的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
springboot+rabbitmq實現(xiàn)智能家居實例詳解
這篇文章主要為大家介紹了springboot+rabbitmq實現(xiàn)智能家居的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-07-07關(guān)于java.math.BigDecimal比較大小問題
這篇文章主要介紹了關(guān)于java.math.BigDecimal比較大小問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07SpringBoot中Mybatis注解一對多和多對多查詢實現(xiàn)示例
這篇文章主要介紹了SpringBoot中Mybatis注解一對多和多對多查詢的實現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-03-03基于SSM實現(xiàn)學(xué)生管理系統(tǒng)
這篇文章主要為大家詳細介紹了基于SSM實現(xiàn)學(xué)生管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-12-12線程局部變量的實現(xiàn)?ThreadLocal使用及場景介紹
這篇文章主要為大家介紹了線程局部變量的實現(xiàn)?ThreadLocal使用及場景詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-01-01淺談SpringCloud的微服務(wù)架構(gòu)組件
這篇文章主要介紹了淺談SpringCloud的微服務(wù)架構(gòu)組件,Spring Cloud根據(jù)分布式服務(wù)協(xié)調(diào)治理的需求成立了許多子項目,每個項目通過特定的組件去實現(xiàn),需要的朋友可以參考下2023-04-04