Go NATS Go 客户端怎样为消息附加请求头
给 NATS Go 消息附加头部,使用 nats.NewMsg(subject) 构造消息,通过 msg.Header.Set 或 Add 写入字段,再调用 nc.PublishMsg(msg)。普通 Publish(subject, data) 只有主题与正文参数,不能靠把元数据拼进 subject 来替代独立消息头。
官方地址:https://nats.io/
本文以发票事件为例:正文放发票编号,头部放追踪标识、内容类型和业务标签。这里的“请求头”指 NATS 消息头;Core NATS 发布订阅也能携带它,不要求消息一定是请求回复,更不代表 HTTP 请求。
先确定主题、正文和头部各自负责什么
Subject 决定订阅匹配,Data 承载业务正文,Header 承载附加元数据。本文约定主题为 demo.invoice.created,正文为 invoice-042,X-Trace-Id 是追踪标识,X-Label 是允许多个值的标签。消息头不会让普通主题订阅自动变成按字段筛选的订阅。
先约定必填字段、单值或多值、长度以及缺失处理,再写生产者和消费者。追踪标识只是调用方提供的数据,不应直接当作授权凭据;敏感身份信息是否允许传播,需要业务另外设计。

连接准备:让服务端支持头部,让订阅先建立
示例使用已经启动的本地 NATS 服务,不包含服务部署与账户配置。在独立 Go 模块中添加依赖,并把下文代码保存为 main.go;已有工程应按自身依赖策略选择和固定版本。
# 在独立示例目录中初始化并加入官方 Go 客户端依赖 go mod init example.com/nats-header-demo go get github.com/nats-io/nats.go # 文件保存后运行;需要本地 NATS 服务已可连接 go run .
连接后用 HeadersSupported() 判断当前服务端能力。不支持时应明确报错,不要静默丢掉业务依赖的字段。示例用 SubscribeSync 创建订阅,并在发布前调用 FlushTimeout,把订阅注册与发布的关系写清楚。网络、权限和连接状态仍可能导致操作失败,每个错误都要向上返回。
构造消息:Set 写单值,Add 写多值
NewMsg 会准备可写的 Header,适合直接添加字段。如果自己写 &nats.Msg{Subject: ...},需要先给 Header 分配非 nil 的 map,再执行写入。不要把 nil Header 的读取和写入混为一谈。
package main
import (
"fmt"
"log"
"time"
"github.com/nats-io/nats.go"
)
func run() error {
// 示例需要本地已启动、允许访问的 NATS 服务。
nc, err := nats.Connect(nats.DefaultURL)
if err != nil { return fmt.Errorf("连接: %w", err) }
defer nc.Close()
if !nc.HeadersSupported() {
return fmt.Errorf("当前连接的服务端不支持消息头")
}
sub, err := nc.SubscribeSync("demo.invoice.created")
if err != nil { return fmt.Errorf("订阅: %w", err) }
defer sub.Unsubscribe()
// 先确认服务端处理了订阅,减少示例中的订阅建立竞态。
if err := nc.FlushTimeout(2 * time.Second); err != nil {
return fmt.Errorf("刷新订阅: %w", err)
}
msg := nats.NewMsg("demo.invoice.created")
msg.Data = []byte("invoice-042")
msg.Header.Set("Content-Type", "text/plain; charset=utf-8")
msg.Header.Set("X-Trace-Id", "trace-invoice-042")
// Add 保留同名字段的多个值,Set 则替换整组值。
msg.Header.Add("X-Label", "billing")
msg.Header.Add("X-Label", "sandbox")
if err := nc.PublishMsg(msg); err != nil {
return fmt.Errorf("发布: %w", err)
}
if err := nc.FlushTimeout(2 * time.Second); err != nil {
return fmt.Errorf("刷新发布: %w", err)
}
got, err := sub.NextMsg(2 * time.Second)
if err != nil { return fmt.Errorf("接收: %w", err) }
// 键名大小写必须与双方约定一致,Values 用于读取全部值。
fmt.Println(got.Header.Get("X-Trace-Id"))
fmt.Println(got.Header.Values("X-Label"))
fmt.Println(string(got.Data))
return nil
}
func main() {
if err := run(); err != nil { log.Fatal(err) }
}
头部操作的关键是 Set 替换同名字段的整组值,Add 追加一个值,Get 取得首值,Values 取得全部值。本文两个 X-Label 使用两次 Add;改成两次 Set,最后只会留下 sandbox。NATS Go 的这些头部操作区分键名大小写,不能因为其设计参考了 http.Header,就假设会自动统一键名。
在这个例子中,若本地服务可连接、订阅和发送均成功,按代码推导应打印三行:
trace-invoice-042
[billing sandbox]
invoice-042
以上为预期结果说明,未在本文制作过程中运行。检查时应同时关注追踪字段、标签完整性和正文,而不是只看到发票编号就认为头部传递成功。
发送结果:PublishMsg 和 Flush 分别说明什么
PublishMsg 返回 nil 不能证明消费者已经完成处理;FlushTimeout 利用连接上的协议往返,等待服务端处理此前发送的数据,也不是业务完成回执。示例中的 NextMsg 只是让当前订阅收到消息,并不代表其他服务已入库、计费或发通知。
这里有两组对象:发送操作包含 PublishMsg 与 FlushTimeout,订阅读取包含 NextMsg、Header.Get、Header.Values 与 Data。PublishMsg 与 FlushTimeout 是连接操作,NextMsg 得到的消息同时包含 Header 和 Data;Get、Values 读取 Header 的不同视图。下图仅展示这些归属和静态关联,不表示业务确认顺序。

如果后续要把示例改为请求回复,用双方定义的回复内容表达业务成功,并设置超时及幂等约定。如果需要持久化和发布确认,应独立选择 JetStream 的发布接口;仅给 Core NATS 消息加一个类似确认的自定义字段,不会改变投递保证。
集成到工程时容易遗漏的约定
| 场景 | 推荐写法或处理 | 核对点 |
|---|---|---|
| 一个追踪标识 | Header.Set | 双方使用同一键名与大小写 |
| 多个业务标签 | Add 写入,Values 读取 | Get 只给首值 |
| 手工构造 Msg | 初始化 Header map | nil map 不能写入 |
| 字段缺失或值为空 | 按业务合同判断 | Get 返回空串不足以区分两种情况 |
| 发布返回成功 | 继续按业务协议取得结果 | 不能据此宣称消费者已完成 |
| 连接重建或能力变化 | 保留发布错误处理 | 启动时的能力判断不替代每次调用错误 |
需要区分字段不存在与空值时,可使用准确键名对 Header 做 map 查找,并检查返回的布尔值和切片内容。不要把空字符串当成必填字段已经通过校验。
每条消息创建自己的可写头部。若多个 goroutine 共用同一个 Header map 并修改,会引入普通 Go map 的并发访问问题;共用指针或浅拷贝并不能隔离其中的切片。需要复制时,逐个复制键和值切片,发布前完成字段构造,并避免在发布期间修改消息。
常见疑问与落地清单
能直接在 Publish 的 data 中加 JSON 字段吗?可以,那属于正文格式设计。是否放 Header 取决于元数据合同;消费者不能自动从 JSON 读取出 NATS Header。
收到没有头部的消息能读取吗?应允许 Header 为 nil,Get 会得到空串;业务若要求字段必须存在,应显式校验,不能直接写回 nil map。
最终需要保留哪些动作?先定义字段合同,再准备连接和订阅,使用 NewMsg 构造独立消息,检查 PublishMsg 错误,按需要刷新连接并读取消息,最后用业务自己的确认规则判断处理完成。关闭连接前完成所需发送与等待;本文 defer Close 负责结束示例连接,不是异步业务任务的完成保证。
技术依据:官方 Header API、官方 Go 客户端实现、NATS 客户端协议。字段命名、发票事件与业务边界示例为本文原创设计。
Go go-diff 应用补丁后为什么还要看每块匹配结果
- 上一篇
- Go go-diff 应用补丁后为什么还要看每块匹配结果
- 下一篇
- Go NATS Go 订阅的 pending 限额为什么影响慢消费者
-
- Golang · Go教程 | 21分钟前 |
- Go Hamba Avro 怎样使用读者 Schema 读取演进后的记录
- 330浏览 收藏
-
- Golang · Go教程 | 28分钟前 |
- Go go-vcard 怎样设置优先使用的邮箱字段
- 466浏览 收藏
-
- Golang · Go教程 | 30分钟前 |
- Go go-smtp 怎样重置未完成的发送事务
- 178浏览 收藏
-
- Golang · Go教程 | 35分钟前 |
- Go go-message 怎样同时写入纯文本正文和附件
- 434浏览 收藏
-
- Golang · Go教程 | 37分钟前 |
- Go go-imap 怎样把本地邮件追加到指定邮箱
- 240浏览 收藏
-
- Golang · Go教程 | 43分钟前 |
- Go Paho MQTT Go 怎样在重连回调中恢复业务订阅
- 263浏览 收藏
-
- Golang · Go教程 | 45分钟前 |
- Go JetStream Go 客户端怎样监听键值桶变化
- 173浏览 收藏
-
- Golang · Go教程 | 52分钟前 | go · Go 文本差异 go-diff diffmatchpatch
- Go go-diff 怎样按行压缩文本后计算差异
- 479浏览 收藏
-
- Golang · Go教程 | 56分钟前 |
- Go go-pretty 怎样把同一组行导出成 Markdown 表格
- 136浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Go go-runewidth 怎样按显示列数折行
- 273浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Go uniseg 怎样判断一段文本允许换行的位置
- 262浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Go go-i18n 怎样向消息模板传入命名字段
- 262浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 799次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 792次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 878次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 848次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 680次使用
-
- Java 性能优化上线清单:从定位、改造到灰度发布
- 2026-06-11 860浏览
-
- Spring Boot 压测验证:Gatling、JMeter 与性能回归门禁
- 2026-06-11 843浏览
-
- Java NMT 非堆内存排查:Direct Buffer、线程栈与 Metaspace 分析
- 2026-06-11 826浏览
-
- Spring Boot 容器内存优化:JVM 堆、非堆与 MaxRAMPercentage
- 2026-06-11 809浏览
-
- Tomcat 连接与线程参数调优:maxThreads、acceptCount 与 KeepAlive
- 2026-06-11 792浏览

