golang工程——grpc-gateway 转发http header中自定义字段到grpc上下文元数据
http header 转发到 grpc上下文
grpc网关可以将请求体内容转发到grpc对应消息中。那如何获取http header头中的信息,本文将介绍如何将http header转发到grpc上下文并采用拦截器,获取http header中的内容。 有些http header中的内置字段是会转发的比如Authorization,但是狠多自定义字段是转发不了的。
本文实现http header中自定义字段转发到grpc上下文并采用拦截器做个简单鉴权
代码可以参考前面几篇grpc-gateway博客
grpc-gateway入门,环境+简单案例
grpc-gateway proto定义http路由
grpc-gateway定义http路由
网关代码修改
如果要转发http header中的自定义内容,生成的网关代码需要进行修改,增加一些网关服务器选项
- runtime.WithIncomingHeaderMatcher: 请求http header 设置转发哪些到grpc上下文
- runtime.WithOutgoingHeaderMatcher: 响应后,grpc上下文转发到http头部
gateway.go
package gatewayimport ("context""flag""fmt""net/http""github.com/grpc-ecosystem/grpc-gateway/v2/runtime""google.golang.org/grpc""google.golang.org/grpc/credentials/insecure"_ "google.golang.org/grpc/grpclog"gw "user/proto" // Update
)var (// command-line options:// gRPC server endpointgrpcServerEndpoint = flag.String("grpc-server-endpoint", "localhost:50051", "gRPC server endpoint")
)func Run() error {ctx := context.Background()ctx, cancel := context.WithCancel(ctx)defer cancel()// 请求时,将http header中某些字段转发到grpc上下文inComingOpt := runtime.WithIncomingHeaderMatcher(func(s string) (string, bool) {fmt.Println("header:" + s)switch s {case "Service-Authorization":fmt.Println("Service-Authorization hit")return "Service-Authorization", truedefault:return "", false}})// 响应后,grpc上下文转发到http头部outGoingOpt := runtime.WithOutgoingHeaderMatcher(func(s string) (string, bool) {return "", false})// Register gRPC server endpoint// Note: Make sure the gRPC server is running properly and accessiblemux := runtime.NewServeMux(inComingOpt, outGoingOpt)//添加文件上传处理函数mux.HandlePath("POST", "/upload", uploadHandler)opts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}err := gw.RegisterUserHandlerFromEndpoint(ctx, mux, *grpcServerEndpoint, opts)if err != nil {return err}// Start HTTP server (and proxy calls to gRPC server endpoint)return http.ListenAndServe(":8081", mux)
}
文件上传接口修改,因为这是自定义的网关路由接口,需要自己将Header中的字段转发到grpc中
upload.go
package gatewayimport ("context""fmt""github.com/golang/protobuf/jsonpb""google.golang.org/grpc""google.golang.org/grpc/credentials/insecure""google.golang.org/grpc/metadata""io""net/http""user/proto"
)func uploadHandler(w http.ResponseWriter, r *http.Request, pathParams map[string]string) {// 先从request解析文件err := r.ParseForm()if err != nil {http.Error(w, fmt.Sprintf("上传失败:%s", err.Error()), http.StatusInternalServerError)}f, header, err :=r.FormFile("attachment")if err != nil {http.Error(w, fmt.Sprintf("上传失败:%s", err.Error()), http.StatusInternalServerError)}defer f.Close()// 访问grpc server端, 实际生产用连接池conn, err := grpc.Dial(*grpcServerEndpoint, grpc.WithTransportCredentials(insecure.NewCredentials()))if err != nil {http.Error(w, fmt.Sprintf("上传失败:%s", err.Error()), http.StatusInternalServerError)}defer conn.Close()c := proto.NewUserClient(conn)ctx := context.Background()ctx = metadata.NewOutgoingContext(ctx, metadata.New(map[string]string{"file_name":header.Filename,"service-authorization":r.Header.Get("Service-Authorization"),}))stream, err := c.Upload(ctx)if err != nil {http.Error(w, fmt.Sprintf("上传失败:%s", err.Error()), http.StatusInternalServerError)}// 读文件流 转发给grpcbuf := make([]byte, 512)for {n, err := f.Read(buf)if err != nil && err != io.EOF{http.Error(w, fmt.Sprintf("上传失败:%s", err.Error()), http.StatusInternalServerError)}if n == 0 {break}stream.Send(&proto.UploadRequest{Content: buf[:n],Size: int64(n),})}res, err := stream.CloseAndRecv()if err != nil {http.Error(w, fmt.Sprintf("上传失败:%s", err.Error()), http.StatusInternalServerError)}m := jsonpb.Marshaler{}str, _ := m.MarshalToString(res)if err != nil {http.Error(w, fmt.Sprintf("上传失败:%s", err.Error()), http.StatusInternalServerError)}w.Header().Add("Content-Type", "application/json")fmt.Fprintf(w, str)}
grpc服务代码修改
拦截器,从上下文中获取元数据进行业务操作即可
interceptor.go
package serverimport ("context""errors""fmt""google.golang.org/grpc""google.golang.org/grpc/metadata""strings"
)func UnaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {err = auth(ctx)if err != nil {return nil, err}return handler(ctx, req)
}func StreamInterceptor(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {err := auth(ss.Context())if err != nil {return err}return handler(srv, ss)
}func auth(ctx context.Context) error {md, ok := metadata.FromIncomingContext(ctx)fmt.Println("meta:", md)// 实际应用中,返回前端提示需模糊化,详细错误可以打印日志if !ok {return errors.New("获取元数据失败,身份校验失败")}// 转发过来都是小写authorization := md["service-authorization"]if len(authorization) < 1 {return errors.New("获取身份令牌失败,身份校验失败")}token := strings.TrimPrefix(authorization[0], "Bearer ")if token != bearerToken {return errors.New("身份令牌对比失败,身份校验失败")}return nil
}// 测试用
var bearerToken = "sdfdlsdhgeiasdxzasqqqy2ybfhhu2gyvb"
并将拦截器注册到grpc服务中
s := grpc.NewServer(grpc.UnaryInterceptor(server.UnaryInterceptor), grpc.StreamInterceptor(server.StreamInterceptor))
重点还是网关代码修改,增加转发header的逻辑。
相关文章:
golang工程——grpc-gateway 转发http header中自定义字段到grpc上下文元数据
http header 转发到 grpc上下文 grpc网关可以将请求体内容转发到grpc对应消息中。那如何获取http header头中的信息,本文将介绍如何将http header转发到grpc上下文并采用拦截器,获取http header中的内容。 有些http header中的内置字段是会转发的比如Au…...

CPU眼里的C/C++: 1.3 汇编级单步调试函数执行过程
1. 目的 2. 基于 GDB 的汇编级单步调试 原始代码 #include <stdio.h>long test() {long a 1;a 2;return a; }int main() {int ret test();printf("test return %d\n", ret);return 0; }关键 gdb 命令 si 指令执行汇编级的单步调试info registers 读取寄…...

数据结构时间复杂度(补充)和空间复杂度
Hello,今天事10月27日,距离刚开始写博客已经过去挺久了,我也不知道是什么让我坚持这么久,但是学校的课真的很多,很少有时间多出来再学习,有些科目马上要考试了,我还不知道我呢不能过哈哈哈&…...

Mac-postman存储文件目录
今天postman弹窗要求登录账号才可访问之前的API文档数据。 但是这postman的账号又是前同事的账号,我没有他的账号和密码啊。 登录了我自己的postman账号后,所有的api文档都不见了....我服了。 首先去屏幕左上角---> 前往 --->个人 然后键盘按显…...

JAVA面试题简单整理
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、重载和重写的区别一、&和&&的区别一、get和post请求的区别 delete、put一、cookie和session的区别一、Autowired和Resource区别一、”和equals…...
dd命令用法学习,是一个功能强大的工具
dd 命令是一个功能强大的工具,它有许多参数可以用来控制其行为。以下是 dd 命令中常用的一些参数: - ifinputfile:指定输入文件的路径。 - ofoutputfile:指定输出文件的路径。 - bssize:设置每个块的大小。可以使用不同…...

Games104现代游戏引擎笔记 网络游戏进阶架构
Character Movement Replication 角色位移同步 玩家2的视角看玩家1的移动是起伏一截一截,并且滞后的 interpolation:内插值,在两个旧的但已知的状态计算 extrapolation:外插值,本质是预测 内插值:但网络随着…...

Apollo 快速上手指南:打造自动驾驶解决方案
快速上手 概述云端体验登录云端仿真环境 打开DreamView播放离线数据包PNC Monitor 内置的数据监视器cyber_monitor 实时通道信息视图福利活动 主页传送门:📀 传送 概述 Apollo 开放平台是一个开放的、完整的、安全的平台,将帮助汽车行业及自…...
C现代方法(第14章)笔记——预处理器
文章目录 第14章 预处理器14.1 预处理器的工作原理14.2 预处理指令14.3 宏定义14.3.1 简单的宏14.3.2 带参数的宏14.3.3 #运算符14.3.4 ##运算符14.3.5 宏的通用属性14.3.6 宏定义中的圆括号14.3.7 创建较长的宏14.3.8 预定义宏14.3.9 C99中新增的预定义宏14.3.10 空的宏参数(C…...

Kafka KRaft模式探索
1.概述 Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者在网站中的所有动作流数据。其核心组件包含Producer、Broker、Consumer,以及依赖的Zookeeper集群。其中Zookeeper集群是Kafka用来负责集群元数据的管理、控制器的选举等。 2.内容…...

LVS-keepalived实现高可用
概念: 本章核心: Keepalived为LVS应运而生的高可用服务。LVS的调度无法做高可用,预算keepalived这个软件,实现了调度器的高可用。 但是:Keeplived不是专门为LVS集群服务的,也可以做其他服务器的高可用 LVS…...
Linux内核驱动开发的需要掌握的知识点
Linux内核驱动开发是一项复杂而有挑战性的任务,需要掌握多方面的知识和技能。下面是一些需要掌握的关键知识点,这些知识将有助于你成功地开发Linux内核驱动程序。 1. Linux内核基础知识 首先,了解Linux内核的基础知识至关重要。这包括Linux…...

nginx 动静分离 防盗链
一、动静分离环境准备静态资源配置(10.36.192.169)安装nginx修改配置文件重启nginx 动态资源配置(192.168.20.135)yum安装php修改nginx配置文件重启nginx nginx代理机配置(192.168.20.134)修改nginx子自配置文件重启nginx 客户端访问 二、防盗链nginx防止…...
MYSQL(索引篇)
一、什么是索引 索引是一种数据结构,它用来帮助MYSQL更高效的获取数据 采用索引可以提高数据检索的效率,降低IO成本 通过索引对数据排序,降低数据排序成本,降低CPU消耗 常见的有:B树索引、B树索引、哈希索引。其中Inno…...

Java API访问HDFS
一、下载IDEA 下载地址:https://www.jetbrains.com/idea/download/?sectionwindows#sectionwindows 拉到下面使用免费的IC版本即可。 运行下载下来的exe文件,注意安装路径最好不要安装到C盘,可以改成其他盘,其他选项按需勾选即可…...

高三高考免费试卷真题押题知识点合集
发表于安徽 温馨提示:有需要的真题试卷可联系本人,百卷内上免费资源。 感觉有用的下方三连,谢谢 。 免费版卷有6-60卷每卷平均4-30页 高三免费高三地理高三英语高三化学高三物理高三语文高三历史高三政治高三数学高三生物 付费版卷有1…...
css 计算函数属性:calc() 不起效 原因
踩坑:注意事项(- 减号或加号前后需要空格!!!) calc(100% - 251px); 这里错误写法中-两边没加空格,导致width不生效。但并不是所有运算符间都需要加空格,只有 和 - 需要加空格,因为运算允许负…...

2、TB6600驱动器介绍【51单片机控制步进电机-TB6600系列】
摘要:本节介绍TB6600驱动器界面及关键参数设置 一、驱动器功能界面 二、关键参数 输入电压:DC9-42V 输出电流:0.5-4A 最大功耗:160W 细分设置:1,2/A,2/B,4,8,16,32 工作温度:-10~45C 信号口驱动电流&…...

Vue3:将表格数据下载为excel文件
需求 将表格数据或者其他形式的数据下载为excel文件 技术栈 Vue3、ElementPlus、 实现 1、安装相关的库 下载xlsx 和 file-saver 库 npm install -S file-saver npm install -S xlsx引入XLSX库和FileSaver库 import XLSX from xlsx; import FileSaver from file-saver;…...

vue+Fullcalendar
vueFullcalendar: vueFullcalendar项目代码https://gitee.com/Oyxgen404/vue--fullcalendar.git...

label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...

关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...

高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...

零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...
《Offer来了:Java面试核心知识点精讲》大纲
文章目录 一、《Offer来了:Java面试核心知识点精讲》的典型大纲框架Java基础并发编程JVM原理数据库与缓存分布式架构系统设计二、《Offer来了:Java面试核心知识点精讲(原理篇)》技术文章大纲核心主题:Java基础原理与面试高频考点Java虚拟机(JVM)原理Java并发编程原理Jav…...