gRPC中interceptor拦截器的总结和实践

news2024/11/27 17:50:45

一、使用场景

gRPC中的interceptor拦截器分为客户端拦截器和服务端拦截器,分别是在客户端和服务端的请求被发送出去之前进行处理的逻辑。常见的使用场景有:(1)请求日志记录及监控;(2)添加请求头数据、以便代理转发使用;(3)请求或者结果重写。

二、原理分析

1.interceptor介绍

拦截器是调用在还没有到达目的地之前进行处理的逻辑,类似于Spring框架中存在的Interceptor。

gRPC 拦截器主要分为两种:客户端拦截器(ClientInterceptor),服务端拦截器(ServerInterceptor),顾名思义,分别于请求的两端执行相应的前拦截处理。

2.使用方法说明

2.1.ClientInterceptor 源码

@ThreadSafe
public interface ClientInterceptor {

  <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
      MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next);
}

它只有一个方法:interceptCall,对于注册了相应拦截器的客户端调用,都要经过这个方法。

参数:

1、method:MethodDescriptor 类型,标示请求方法。包括方法全限定名称、请求服务名称、请求、结果、序列化工具、幂等等。

2、callOptions:此次请求的附带信息。

3、next:执行此次 RPC 请求的抽象链接管道(Channel)

返回:

ClientCall,包含请求及结果信息,并且不为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,对于注册了相应拦截器的服务端调用,都要经过这个方法。

参数:

  1. call:ServerCall 对象,包含客户端请求的 MethodDescriptor
  2. headers:请求头信息
  3. next:处理链条上的下一个处理。

三、代码实践

1.实现功能

通过代码实现以下功能:

  1. 使用grpc打印日志;
  2. 获取header信息,返回header信息;
  3. 使用grpc获取ip信息,获取客户端传递过来的信息;

2.服务端实现代码

(1)实现自定义ServerGrpcInterceptor

只需要实现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中的参数进行业务处理
        Map map = new HashMap();
        map.put("00000001", "admin");

        //获取header中参数
        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,关闭此连接");
            serverCall.close(Status.DATA_LOSS,metadata);
        }
        //获得token去中查询
        String userInfo = map.get(metadata.get(userId));
        if(StringUtil.isNullOrEmpty(userInfo)){
            System.err.println("客户端token错误,关闭此连接");
            serverCall.close(Status.DATA_LOSS,metadata);
        }

        //服务端写回参数
        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.客户端实现代码

(1)实现自定义ClientGrpcInterceptor

只需要实现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.请求参数放到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.验证结果

服务端请求结果:

E2B6C26B-1689-40D7-A180-4E9019DA0EDA

客户端请求结果:

11FC41DE-706F-45FB-8DDD-D3469FB093D2

代码地址:https://github.com/yangnk/SpringBoot_Learning/tree/master/GRPCDemo


参考资料

  1. java版gRPC实战之二:服务发布和调用:https://cloud.tencent.com/developer/article/1892790
  2. gRPC 拦截器能做些什么?:https://www.cnblogs.com/niejunlei/p/14995433.html
  3. grpc java 拦截器的使用(包含server&client):https://blog.csdn.net/mengxb12138/article/details/77991472
  4. gRPC客户端拦截器的踩坑心得:https://juejin.cn/post/7145375285091762207

    本文由博客一文多发平台 OpenWrite 发布!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/847396.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++初阶语法——引用,从此和指针说byebye

前言&#xff1a;相信学过C语言的同学肯定被指针深深折磨过&#xff0c;从一级指针到二级指针&#xff0c;数组指针&#xff0c;函数指针等等&#xff0c;可谓是谈针色变。而在C中&#xff0c;使用引用代替了指针的使用&#xff0c;大大降低了我们学习的难度。 引用 一.什么是…

阿里云二级域名配置

阿里云二级域名配置 首先需要进入阿里云控制台的域名管理 1.选择域名点击解析 2.添加记录 3.选择A类型 4.主机记录设置【可以aa.bb或者aa.bb.cc】 到时候会变成&#xff1a;aa.bb.***.com 5.解析请求来源设置为默认 6.记录值 设置为要解析的服务器的ip地址 7.TTL 默认即…

知网行政部门主管_《天津教育》投稿指南

知网行政部门主管_《天津教育》投稿指南 一、《天津教育》期刊简介&#xff1a; 主管单位&#xff1a;天津市教育委员会 主办单位&#xff1a;天津教育报刊社 国际标准刊号ISSN:0493-2099 国内统一刊号CN:12-1044/G4 邮发代号6-9 出版周期&#xff1a;旬刊 出版地&…

Linux usb设备固定端口号

Linux usb设备固定端口号 一:/sys/bus/usb/devices/二:设备信息三:固定usb设备名方法 一:/sys/bus/usb/devices/ 信息显示如下 1-0:1.0 1&#xff1a;表示 1 号总线&#xff0c;或者说 1 号 Root Hub0&#xff1a;表示端口号1&#xff1a;表示配置号0&#xff1a;表示接口号命…

【FeatureBooster】Boosting Feature Descriptors with a Lightweight Neural Network

这篇论文介绍了一种轻量级网络&#xff0c;用于改进同一图像中关键点的特征描述符。该网络以原始描述符和关键点的几何属性作为输入&#xff0c;使用基于多层感知器&#xff08;MLP&#xff09;的自我增强阶段和基于Transformer的交叉增强阶段来增强描述符。增强后的描述符可以…

搭建Repo服务器

1 安装repo 参考&#xff1a;清华大学开源软件镜像站:Git Repo 镜像使用帮助 2 创建manifest仓库 2.1 创建仓库 git init --bare manifest.git2.2 创建default.xml文件 default.xml文件内容&#xff1a; <?xml version"1.0" encoding"UTF-8" ?…

java之junit Test

JUnit测试简介 1.什么是单元测试 单元测试是针对最小的功能单元编写测试代码Java程序最小的功能单元是方法单元测试就是针对单个Java方法的测试 2.测试驱动开发 3.单元测试的好处 确保单个方法运行正常如果修改了方法代码&#xff0c;只需确保其对应的单元测试通过测试代码…

QtCreator5.15.2新建工程没有pro文件

Qt系列文章目录 文章目录 Qt系列文章目录前言一、解决办法参考 前言 最近新安装了Qt5.15.2版本&#xff0c;使用她创建新工程发现居然没有pro工程文件&#xff0c;取而代之的是CMakeLists.txt&#xff0c;文件里面的代码几乎看不懂&#xff0c;不知道如何在CMakeLists.txt加入…

CentOS虚拟机 NAT模式连网

1、查看本地VMnet8的网络信息 cmd ipconfig2、编辑VMware虚拟网络编辑器 &#xff08;1&#xff09;打开网络编辑器 &#xff08;2&#xff09;打开NET设置 &#xff08;3&#xff09;修改网络配置 修改子网ip和windows查到的ip的最后一位不一样就行和子网掩码照抄 3、在VMw…

P1993 小 K 的农场(差分约束)(内附封面)

小 K 的农场 题目描述 小 K 在 MC 里面建立很多很多的农场&#xff0c;总共 n n n 个&#xff0c;以至于他自己都忘记了每个农场中种植作物的具体数量了&#xff0c;他只记得一些含糊的信息&#xff08;共 m m m 个&#xff09;&#xff0c;以下列三种形式描述&#xff1a;…

SRV6 BE

实验目的:通过SRV6 BE实现CE之间的ipv4网络互访 步骤1&#xff1a;配置ISP网络设备的ipv6地址 步骤2&#xff1a;配置ISP网络的IGP协议&#xff08;ISIS ipv6&#xff09;设备配置前先在每台设备上面 undo dcn PE1: isis 1cost-style widenetwork-entity 49.0001.0000.0000…

Substack 如何在去中心化内容创作领域掀起波澜

面对数字内容广告化的困境&#xff0c;Substack回归做内容的初心&#xff0c;通过产品和平台双轮驱动&#xff0c;重塑一个去中心化的多元文化内容聚集地&#xff0c;实现了增长突破。其核心策略在于先使用简洁的创作工具赋能内容生产&#xff0c;进而通过平台的互动机制促进用…

【Python基础教程】super()函数的正确使用方法

前言 大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 1.super(本身类名,self).方法名(参数)这样就可以调用父类的方法和参数了,super()内也可不加参数 2.规律是super是按调用的次序执行&#xff0c;super后面的语句是逆向执行的。 有2段示例代码&#xff0c;不同的在于value有没…

高忆管理:股票成交量怎么看?

股票成交量是衡量股票商场生意活泼度的重要目标之一。通过调查股票成交量的巨细和改变趋势&#xff0c;能够帮助出资者更好地了解商场状况和出资方向&#xff0c;从而做出更正确的出资决策。那么&#xff0c;股票成交量怎么看&#xff1f;本文将从多个视点为您剖析。 一、股票成…

ZyjDataLink 全量MySQL同步程序 - 开发过程 01

开发过程由本人从 架构设计 到 代码实现 独立完成&#xff0c;通过该博客记录分享开发经验 ZyjDataLink 当前的目标是做到 MySQL大数据量的快速同步&#xff0c;后期希望扩展的功能 高度可操作性&#xff0c;融入增量数据库同步&#xff0c;跨数据库同步 ZyjDataLink 需求分析…

python数据分析报告 范文,python数据分析报告+代码

大家好&#xff0c;本文将围绕python数据分析期末大作业报告展开说明&#xff0c;python数据分析期末大作业是一个很多人都想弄明白的事情&#xff0c;想搞清楚python数据分析报告怎么写需要先了解以下几个事情。 背景 虽然用Python开发爬虫脚本&#xff0c;顺利把某房产网站的…

小学生作业随机加减乘除运算计算习题答案 html源码

小学生作业随机加减乘除运算计算习题答案 html源码 这道题目提供了多种选项,包括运算符和输入的运算数范围。题目数量也可以选择。如果你选择好了选项,就可以点击出题按钮进行练习。 为了方便,题目答案可以打印出来。但是,如果隐藏了横线,就会去除等号后面的下划线。推荐使用…

Java中实现图片和Base64的互相转化

文章目录 前言一、代码二、测试三、结果 前言 公司项目中用到了实名认证此&#xff0c;采用的第三方平台。后端中用到的单项功能为身份证信息人像对比功能&#xff0c;在写demo的过程中发现&#xff0c;它们所要求的图片信息为base64编码格式。 一、代码 package com.bajiao…

QGIS二次开发二:不重新编译QGIS进行二次开发

目录 一、下载OSGeo4W 二、配置VS 三、测试代码 四、补充&#xff1a;配置QT插件 五、导出项目为模板 六、Release模式的一个问题解决 由于重新编译QGIS对于初学者来说还是有一定难度&#xff0c;因此这里介绍另外一种不编译QGIS也能够二次开发的方法&#xff0c;不需要…

世界算力简史(上)

1946年2月14日&#xff0c;在美国宾夕法尼亚州东南部的费城&#xff0c;人们正在像以往一样正常工作和生活。 忽然&#xff0c;他们发现&#xff0c;房间里的灯暗了下来。 刚刚经历过二战的人们&#xff0c;对这种情况习以为常。他们心想&#xff1a;“是不是哪里的电力线路又坏…