当前位置: 首页 > news >正文

go-zero开发入门之网关往rpc服务传递数据

go-zero 的网关往 rpc 服务传递数据时,可以使用 headers,但需要注意前缀规则,否则会发现数据传递不过去,或者对方取不到数据。

go-zero 的网关对服务的调用使用了第三方库 grpcurl,入口函数为 InvokeRPC:

grpcurl.InvokeRPC(r.Context(), source, cli.Conn(), rpcPath, s.prepareMetadata(r.Header), handler, parser.Next)

调用在 https://github.com/zeromicro/go-zero/blob/master/gateway/server.go 中进行的,上述调用会处理 HTTP 的 headers 数据,对于不是以字符串“Grpc-Metadata-”打头的会过滤掉,对于以字符串“Grpc-Metadata-”打头的会将“Grpc-Metadata-”转为“gateway-”。

// go-zero/gateway/internal/headerprocessor.go
// ProcessHeaders builds the headers for the gateway from HTTP headers.
func ProcessHeaders(header http.Header) []string {var headers []stringfor k, v := range header {if !strings.HasPrefix(k, metadataHeaderPrefix) { // 判断是否包含了前缀“Grpc-Metadata-”continue // 如果没有前缀“Grpc-Metadata-”则直接过滤丢弃掉}// 将前缀“Grpc-Metadata-”替换为前缀“gateway-”key := fmt.Sprintf("%s%s", metadataPrefix, strings.TrimPrefix(k, metadataHeaderPrefix))for _, vv := range v {headers = append(headers, key+":"+vv)}}return headers
}

函数 MetadataFromHeaders 负责从 headers 解码数据:

// https://github.com/fullstorydev/grpcurl/blob/master/grpcurl.go
func MetadataFromHeaders(headers []string) metadata.MD {md := make(metadata.MD)for _, part := range headers {if part != "" {pieces := strings.SplitN(part, ":", 2)if len(pieces) == 1 {pieces = append(pieces, "") // if no value was specified, just make it "" (maybe the header value doesn't matter)}headerName := strings.ToLower(strings.TrimSpace(pieces[0]))val := strings.TrimSpace(pieces[1])if strings.HasSuffix(headerName, "-bin") {if v, err := decode(val); err == nil {val = v}}md[headerName] = append(md[headerName], val)}}return md
}
// https://github.com/fullstorydev/grpcurl/blob/master/invoke.go
func InvokeRPC(ctx context.Context, source DescriptorSource, ch grpcdynamic.Channel, methodName string,headers []string, handler InvocationEventHandler, requestData RequestSupplier) error {md := MetadataFromHeaders(headers)svc, mth := parseSymbol(methodName)if svc == "" || mth == "" {return fmt.Errorf("given method name %q is not in expected format: 'service/method' or 'service.method'", methodName)}dsc, err := source.FindSymbol(svc)if err != nil {// return a gRPC status error if hasStatus is trueerrStatus, hasStatus := status.FromError(err)switch {case hasStatus && isNotFoundError(err):return status.Errorf(errStatus.Code(), "target server does not expose service %q: %s", svc, errStatus.Message())case hasStatus:return status.Errorf(errStatus.Code(), "failed to query for service descriptor %q: %s", svc, errStatus.Message())case isNotFoundError(err):return fmt.Errorf("target server does not expose service %q", svc)}return fmt.Errorf("failed to query for service descriptor %q: %v", svc, err)}sd, ok := dsc.(*desc.ServiceDescriptor)if !ok {return fmt.Errorf("target server does not expose service %q", svc)}mtd := sd.FindMethodByName(mth)if mtd == nil {return fmt.Errorf("service %q does not include a method named %q", svc, mth)}handler.OnResolveMethod(mtd)// we also download any applicable extensions so we can provide full support for parsing user-provided datavar ext dynamic.ExtensionRegistryalreadyFetched := map[string]bool{}if err = fetchAllExtensions(source, &ext, mtd.GetInputType(), alreadyFetched); err != nil {return fmt.Errorf("error resolving server extensions for message %s: %v", mtd.GetInputType().GetFullyQualifiedName(), err)}if err = fetchAllExtensions(source, &ext, mtd.GetOutputType(), alreadyFetched); err != nil {return fmt.Errorf("error resolving server extensions for message %s: %v", mtd.GetOutputType().GetFullyQualifiedName(), err)}msgFactory := dynamic.NewMessageFactoryWithExtensionRegistry(&ext)req := msgFactory.NewMessage(mtd.GetInputType())handler.OnSendHeaders(md)ctx = metadata.NewOutgoingContext(ctx, md)stub := grpcdynamic.NewStubWithMessageFactory(ch, msgFactory)ctx, cancel := context.WithCancel(ctx)defer cancel()if mtd.IsClientStreaming() && mtd.IsServerStreaming() {return invokeBidi(ctx, stub, mtd, handler, requestData, req)} else if mtd.IsClientStreaming() {return invokeClientStream(ctx, stub, mtd, handler, requestData, req)} else if mtd.IsServerStreaming() {return invokeServerStream(ctx, stub, mtd, handler, requestData, req)} else {return invokeUnary(ctx, stub, mtd, handler, requestData, req)}
}

网关可如下实现:

newReq := r.WithContext(r.Context())
newReq.Header.Set("Grpc-Metadata-myuid", userId)
next.ServeHTTP(w, newReq)

服务端的实现:

vals := metadata.ValueFromIncomingContext(l.ctx, "gateway-myuid")
userId := vals[0]

相关文章:

go-zero开发入门之网关往rpc服务传递数据

go-zero 的网关往 rpc 服务传递数据时,可以使用 headers,但需要注意前缀规则,否则会发现数据传递不过去,或者对方取不到数据。 go-zero 的网关对服务的调用使用了第三方库 grpcurl,入口函数为 InvokeRPC: …...

Word插件-好用的插件-批量插入图片-大珩助手

现有100张图片,需要批量插入word中,并在word中以每页6张图片的形式呈现,请问怎样做? 使用word大珩助手,多媒体-插入图片,根据图片的长宽,选择连续图片、一行2个图或一行3个图,可一次…...

小程序域名SSL证书能用免费的吗?

众所周知,目前小程序要求域名强制使用https协议,否则无法上线。但是对于大多数开发者来说,为每一个小程序都使用上付费的SSL证书,也是一笔不小的支出。那么小程序能使用免费的SSL证书吗? 答案是肯定的。目前市面上可选…...

selenium自动化(中)

显式等待与隐式等待 简介 在实际工作中等待机制可以保证代码的稳定性,保证代码不会受网速、电脑性能等条件的约束。 等待就是当运行代码时,如果页面的渲染速度跟不上代码的运行速度,就需要人为的去限制代码执行的速度。 在做 Web 自动化时…...

uniapp app将base64保存到相册,uniapp app将文件流保存到相册

如果是文件流可以先转base64详情见>uniapp 显示文件流图片-CSDN博客 onDown(){let base64 this.qrcodeUrl ; // base64地址const bitmap new plus.nativeObj.Bitmap("test");bitmap.loadBase64Data(base64, function() {const url "_doc/" new Dat…...

Navicat 技术指引 | 适用于 GaussDB 分布式的服务器对象的创建/设计

Navicat Premium(16.3.3 Windows版或以上)正式支持 GaussDB 分布式数据库。GaussDB分布式模式更适合对系统可用性和数据处理能力要求较高的场景。Navicat 工具不仅提供可视化数据查看和编辑功能,还提供强大的高阶功能(如模型、结构…...

五、HotSpot细节实现

一、并发标记与三色标记 问题:三色标记到底发生在什么阶段,替代了什么。并发标记 1、并发标记( Concurrent Marking) 从 GC Root 开始对堆中对象进行可达性分析,递归扫描整个堆里的对象图,找出要回收的对象,这阶段耗…...

DRBD分布式存储实验

DRBD DRBD的全称为:Distributed Replicated Block Device (DRBD) 分布式块设备复制 与心跳连接结合使用,构建高可用性(HA)的集群。 实现方式是通过网络来镜像(mirror)整个设备。它允许用户在远程机器上建立一个本地块设备的实时镜像。DRBD负责接收数据…...

go的结构体作为返回值

结构体有两种方式作为返回值 结构体结构体指针 代码 package mainimport ("fmt" )type SS struct {Name stringAge int }func getInfo() (*SS) {var ac SS{}ac.Age 1return &ac }func getInfo1() (aa *SS) {aa.Age 1return }func getInfo2() (SS) {var ac…...

uniapp的subnvue苹果适配(ios)谷歌地图问题

谷歌地图,google地图,调整宽度。这个适配花了点时间,苹果IOS宽度一直无效失灵,赶紧记录分享,很坑。可能所有的ios的subnvue适配都这样。看了网上很多方法无效,最终找到试出答案。 pages.json的配置宽度无效…...

项目实战之RabbitMQ重试机制进行消息补偿通知

🧑‍💻作者名称:DaenCode 🎤作者简介:啥技术都喜欢捣鼓捣鼓,喜欢分享技术、经验、生活。 😎人生感悟:尝尽人生百味,方知世间冷暖。 文章目录 🌟架构图&#x…...

MySQL之数据库的创建指令

创建数据库 #创建数据库指令: CREATE DATABASE hsp_db1 #创建名字为关键字的数据库,为规避关键字,可以使用反引号 CREATE DATABASE CREATE#删除数据库指令: DROP DATABASE hsp_db1 DROP DATABASE CREATE如果不指定在这里插入代码片…...

[网络安全]批处理(脚本)编写

Windows DOS命令Linux 一.作用: 自上而下成批次处理每一条命令,直到执行到最后一条 二.如何创建批处理: 扩展名:.bat创建办法:新建一个记事本,把扩展名改为 .bat 三.编辑方法: 右击 -编辑 1).一行一个命令 四.批处理命令: pause 暂停 (及时后面有命令,也不执行)echo …...

事件驱动架构 vs. RESTful架构:通信模式对比与选择

1. 通信风格 事件驱动架构(EDA) 是一种异步通信风格,组件之间通过产生和消费事件进行通信。 事件是表示系统中重大变化或事件的消息,并分发给感兴趣的组件。这种通信模型允许系统的不同部分之间进行解耦和动态交互。 组件充当事件…...

代码随想录算法训练营第五十二天| 300 最长递增子序列 674 最长连续递增子序列 718 最长重复子数组

目录 300 最长递增子序列 674 最长连续递增子序列 718 最长重复子数组 300 最长递增子序列 class Solution { public:int lengthOfLIS(vector<int>& nums) {vector<int>dp(nums.size(),1);//以i结尾的最长递增子序列的长度for(int i 0;i < nums.size()…...

leetcode 101.对称二叉树

学习这部分还是要多画图&#xff0c;多思考 101.对称二叉树 题目 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 题目链接 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 文字 和 画图 分析 明确结束条件和继续递归条件 判断是否对称…...

【本人新书】《OpenCV应用开发:入门、进阶与工程化实践》

写作初心 OpenCV作为开源的计算机视觉框架已经有超过20年的发展历程&#xff0c;OpenCV4是OpenCV目前为止最重要的里程碑版本。OpenCV4不仅包含了传统图像处理、图像分析、特征提取等模块的各种主流算法算子&#xff0c;还包含了深度学习模型部署与加速支持模块&#xff0c;兼…...

【Linux系统编程】进度条的编写

目录 一&#xff0c;进度条的必备知识 1&#xff0c;缓冲区的粗略介绍 2&#xff0c;回车与换行 二&#xff0c;进度条的初步制作 1&#xff0c;进度条的初步矿建 2&#xff0c;进度条的版本一 3&#xff0c;进度条的版本二 一&#xff0c;进度条的必备知识 1&#xff…...

互斥锁的原理

互斥锁&#xff08;Mutex&#xff0c;全称Mutual Exclusion&#xff09;是一种同步机制&#xff0c;用于确保在任意时刻&#xff0c;只有一个线程可以访问共享资源&#xff0c;从而防止数据竞争和不一致性。互斥锁的基本思想是在进入临界区之前&#xff0c;先获取锁&#xff1b…...

Win10的SVN Adapter V1.0 中黄色感叹号 -- 解决

大部分都问题都可以通过&#xff1a; 关闭 SVN Adapter V1.0 在下载最新的 SVNDrv.sys替换 C:\Windows\System32\drivers 中的同名文件启动 SVN Adapter V1.0 就能成功 但是部分人的电脑 SVN Adapter V1.0 是有感叹号的&#xff0c;说明注册表有问题 先用 CCleaner 修复注册表…...

经典美剧《暗黑》1-3季4K中英字幕 网盘发送

对《暗黑》任何“烧脑”“神剧”“开挂”的标签都是极其肤浅的论断。 看懂“暗黑”&#xff0c;已然不只是对众多人物关系线的梳理&#xff0c;对单个人物本身时间线的捋顺&#xff0c;它已经站在了哲学或者说神学的山巅尽量地发出凡人能够接受的光波和光谱。 是爱因斯坦相对论…...

Linux:模式通配符 * 和globstar **(bash4新增)的使用

相关文章 Linux专栏https://blog.csdn.net/weixin_45791458/category_12234591.html 在bash的使用过程中&#xff0c;模式通配符可以说是最常见、也最实用的一类功能。很多时候我们在命令行里处理文件&#xff0c;并不是靠把完整文件名一个个手工敲出来&#xff0c;而是通过ba…...

AI辅助开发:看快马AI如何像“走马观碑”一样快速解析需求并生成项目

AI辅助开发&#xff1a;看快马AI如何像"走马观碑"一样快速解析需求并生成项目 最近在InsCode(快马)平台体验了一把AI辅助开发的完整流程&#xff0c;感觉就像亲眼见证了"走马观碑"这个成语在现代技术中的生动演绎。传统意义上的走马观碑形容人记忆力超群、…...

盘点 | 2026顶会顶刊机器人触觉:聚焦五条技术主线

2026年顶会顶刊释放的五大「触觉」关键信号 ——从静态识别到动态闭环 目录 01 元学习赋能机器人触觉识别&#xff0c;精度与泛化性俱佳 ICRA2026 | Tactile Recognition of Both Shapes and Materials with Automatic Feature Optimization-Enabled Meta Learning 研究方…...

Obsidian插件i18n:终极指南,让英文插件说中文的完整解决方案

Obsidian插件i18n&#xff1a;终极指南&#xff0c;让英文插件说中文的完整解决方案 【免费下载链接】obsidian-i18n 项目地址: https://gitcode.com/gh_mirrors/ob/obsidian-i18n 你是否曾因Obsidian插件全是英文界面而感到困扰&#xff1f;数据显示超过83%的Obsidian…...

双向互转|IEC104↔Modbus 工业网关,电力 / 工业现场一键通联

一、产品核心定位三格电子推出SG-IEC104-TCP与SG-TCP-IEC104两款工业级网关&#xff0c;专为电力、能源、智能制造场景打造&#xff0c;实现IEC104 与 Modbus 双向协议转换&#xff0c;兼容 DLT645 电表采集&#xff0c;支持 MQTT 上云&#xff0c;打通电力主站与现场设备的数据…...

FRCRN语音降噪工具实战教程:单麦16k音频一键去噪保姆级指南

FRCRN语音降噪工具实战教程&#xff1a;单麦16k音频一键去噪保姆级指南 1. 快速了解FRCRN语音降噪 你是不是经常遇到这样的困扰&#xff1a;录制的语音通话背景噪音太大&#xff0c;播客内容被环境声干扰&#xff0c;或者重要的会议录音听不清楚人声&#xff1f;FRCRN语音降噪…...

收藏必备!小白程序员轻松入门大模型:从零排查RAG检索问题

本文针对RAG系统上线后常见的检索问题&#xff0c;提出了从源头到后处理的排查思路。文章首先强调文档入库的重要性&#xff0c;接着深入分析向量化和检索召回环节的常见错误&#xff0c;如模型不一致、表述差异等&#xff0c;并给出解决方案。最后&#xff0c;文章还关注排序和…...

终极优化指南:WeChatExtension-ForMac从卡顿到流畅的蜕变之旅

终极优化指南&#xff1a;WeChatExtension-ForMac从卡顿到流畅的蜕变之旅 【免费下载链接】WeChatExtension-ForMac A plugin for Mac WeChat 项目地址: https://gitcode.com/gh_mirrors/we/WeChatExtension-ForMac WeChatExtension-ForMac是一款专为Mac版微信打造的插件…...

如何全面提升GTA5游戏体验:YimMenu安全使用与功能优化终极指南

如何全面提升GTA5游戏体验&#xff1a;YimMenu安全使用与功能优化终极指南 【免费下载链接】YimMenu YimMenu, a GTA V menu protecting against a wide ranges of the public crashes and improving the overall experience. 项目地址: https://gitcode.com/GitHub_Trending…...