gRPC中interceptor攔截器的使用教程
一、使用場(chǎng)景
gRPC中的interceptor攔截器分為客戶端攔截器和服務(wù)端攔截器,分別是在客戶端和服務(wù)端的請(qǐng)求被發(fā)送出去之前進(jìn)行處理的邏輯。常見(jiàn)的使用場(chǎng)景有:(1)請(qǐng)求日志記錄及監(jiān)控;(2)添加請(qǐng)求頭數(shù)據(jù)、以便代理轉(zhuǎn)發(fā)使用;(3)請(qǐng)求或者結(jié)果重寫。
二、原理分析
1.interceptor介紹
攔截器是調(diào)用在還沒(méi)有到達(dá)目的地之前進(jìn)行處理的邏輯,類似于Spring框架中存在的Interceptor。
gRPC 攔截器主要分為兩種:客戶端攔截器(ClientInterceptor),服務(wù)端攔截器(ServerInterceptor),顧名思義,分別于請(qǐng)求的兩端執(zhí)行相應(yīng)的前攔截處理。
2.使用方法說(shuō)明
2.1.ClientInterceptor 源碼
@ThreadSafe
public interface ClientInterceptor {
? <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
? ? ? MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next);
}它只有一個(gè)方法:interceptCall,對(duì)于注冊(cè)了相應(yīng)攔截器的客戶端調(diào)用,都要經(jīng)過(guò)這個(gè)方法。
參數(shù):
1、method:MethodDescriptor 類型,標(biāo)示請(qǐng)求方法。包括方法全限定名稱、請(qǐng)求服務(wù)名稱、請(qǐng)求、結(jié)果、序列化工具、冪等等。
2、callOptions:此次請(qǐng)求的附帶信息。
3、next:執(zhí)行此次 RPC 請(qǐng)求的抽象鏈接管道(Channel)
返回:
ClientCall,包含請(qǐng)求及結(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);
}它只有一個(gè)方法:interceptCall,對(duì)于注冊(cè)了相應(yīng)攔截器的服務(wù)端調(diào)用,都要經(jīng)過(guò)這個(gè)方法。
參數(shù):
- call:ServerCall 對(duì)象,包含客戶端請(qǐng)求的 MethodDescriptor
- headers:請(qǐng)求頭信息
- next:處理鏈條上的下一個(gè)處理。
三、代碼實(shí)踐
1.實(shí)現(xiàn)功能
通過(guò)代碼實(shí)現(xiàn)以下功能:
- 使用grpc打印日志;
- 獲取header信息,返回header信息;
- 使用grpc獲取ip信息,獲取客戶端傳遞過(guò)來(lái)的信息;
2.服務(wù)端實(shí)現(xiàn)代碼
(1)實(shí)現(xiàn)自定義ServerGrpcInterceptor
只需要實(shí)現(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.打印請(qǐng)求方法
??????? log.info("請(qǐng)求方法:{}", serverCall.getMethodDescriptor());
??????? //2.從請(qǐng)求的屬性中獲取遠(yuǎn)程地址
??????? String remoteAddr = serverCall.getAttributes().get(Grpc.TRANSPORT_ATTR_REMOTE_ADDR).toString();
??????? log.info("遠(yuǎn)程地址為:{}", remoteAddr);
??????? //3.獲取header中的參數(shù)進(jìn)行業(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錯(cuò)誤,關(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
通過(guò)@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.客戶端實(shí)現(xiàn)代碼
(1)實(shí)現(xiàn)自定義ClientGrpcInterceptor
只需要實(shí)現(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("請(qǐng)求名稱:{}", method.getFullMethodName());
??????? //2.請(qǐng)求參數(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("請(qǐng)求返回信息為:" + headers);
??????????????????????? super.onHeaders(headers);
??????????????????? }
??????????????? }, headers);
??????????? }
??????? };
??? }
}(2)全局配置ClientGrpcInterceptor
通過(guò)@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.驗(yàn)證結(jié)果
服務(wù)端請(qǐng)求結(jié)果:

客戶端請(qǐng)求結(jié)果:

代碼地址:https://github.com/yangnk/SpringBoot_Learning/tree/master/GRPCDemo
以上就是gRPC中interceptor攔截器的使用教程的詳細(xì)內(nèi)容,更多關(guān)于interceptor攔截器的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
springboot+rabbitmq實(shí)現(xiàn)智能家居實(shí)例詳解
這篇文章主要為大家介紹了springboot+rabbitmq實(shí)現(xiàn)智能家居的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07
關(guān)于java.math.BigDecimal比較大小問(wèn)題
這篇文章主要介紹了關(guān)于java.math.BigDecimal比較大小問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07
SpringBoot中Mybatis注解一對(duì)多和多對(duì)多查詢實(shí)現(xiàn)示例
這篇文章主要介紹了SpringBoot中Mybatis注解一對(duì)多和多對(duì)多查詢的實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-03-03
基于SSM實(shí)現(xiàn)學(xué)生管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了基于SSM實(shí)現(xiàn)學(xué)生管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-12-12
線程局部變量的實(shí)現(xiàn)?ThreadLocal使用及場(chǎng)景介紹
這篇文章主要為大家介紹了線程局部變量的實(shí)現(xiàn)?ThreadLocal使用及場(chǎng)景詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
淺談SpringCloud的微服務(wù)架構(gòu)組件
這篇文章主要介紹了淺談SpringCloud的微服務(wù)架構(gòu)組件,Spring Cloud根據(jù)分布式服務(wù)協(xié)調(diào)治理的需求成立了許多子項(xiàng)目,每個(gè)項(xiàng)目通過(guò)特定的組件去實(shí)現(xiàn),需要的朋友可以參考下2023-04-04
Java Set接口及常用實(shí)現(xiàn)類總結(jié)
Collection的另一個(gè)子接口就是Set,他并沒(méi)有我們List常用,并且自身也沒(méi)有一些額外的方法,全是繼承自Collection中的,因此我們還是簡(jiǎn)單總結(jié)一下,包括他的常用實(shí)現(xiàn)類HashSet、LinkedHashSet、TreeSet的總結(jié)2023-01-01

