Go Gock 怎样给同一路径设置多次不同响应
我第一次给 Gock 写重试测试时,最容易卡住的地方不是响应体,而是“同一个路径为什么第二次请求还拿到第一次的结果”。答案是:可以为完全相同的 HTTP 方法和路径注册多条规则,Gock 会按模拟规则进入池子的 FIFO 声明顺序消费它们;每条规则默认只匹配一次,也可以用 Times(n) 明确保留次数。
Gock 官方地址:https://github.com/h2non/gock
同一路径多次返回不同响应的关键写法,是连续声明相同匹配条件、为每条规则设置清晰的 Times 次数,并让请求按预期顺序消费规则。
为什么同一路径可以返回不同结果
Gock 的匹配不是“相同路径永远绑定一个响应”。官方 README 说明,HTTP 请求会从已声明的模拟期望池中按 FIFO 顺序匹配;请求匹配成功后,当前规则被消费,下一次相同请求就有机会使用下一条规则。因此,第一次可以模拟缓存未命中,第二次可以模拟服务恢复,路径本身不需要改成两个地址。
这里有两个容易混在一起的概念:规则的匹配条件和规则的响应内容。前者可以相同,后者可以不同。只要请求方法、主机、路径及你额外声明的查询参数或请求体都相同,Gock 就会按声明顺序处理这些规则。

用 Times 给连续请求安排不同响应
最小写法是连续写两条相同的 Get 规则,并分别构造响应。示例中第一条返回 503,第二条返回 200;两条都使用 Times(1),这样意图比依赖默认值更清楚。代码只是文章示例,未在本机执行。
package retrytest
import (
"encoding/json"
"net/http"
"testing"
"github.com/h2non/gock"
)
func TestRetryGetsDifferentResponses(t *testing.T) {
// 关闭真实网络,避免规则写错时把请求发到外部服务。
gock.DisableNetworking()
gock.OffAll()
t.Cleanup(gock.OffAll)
// 两条规则的请求条件完全相同,声明顺序决定先后消费关系。
gock.New("https://api.example.test").
Get("/v1/profile").
Times(1).
Reply(http.StatusServiceUnavailable).
JSON(map[string]string{"state": "retry"})
gock.New("https://api.example.test").
Get("/v1/profile").
Times(1).
Reply(http.StatusOK).
JSON(map[string]string{"state": "ready"})
for i, wantStatus := range []int{http.StatusServiceUnavailable, http.StatusOK} {
// 每一轮都访问同一个方法和路径,模拟第一次失败、第二次恢复。
resp, err := http.Get("https://api.example.test/v1/profile")
if err != nil {
t.Fatalf("第 %d 次请求失败: %v", i+1, err)
}
var body map[string]string
if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
resp.Body.Close() // 解码失败时也要释放响应体。
t.Fatalf("第 %d 次响应不是有效 JSON: %v", i+1, err)
}
resp.Body.Close() // 读取完成后关闭模拟响应体。
if resp.StatusCode != wantStatus {
t.Fatalf("第 %d 次状态码=%d,期望=%d", i+1, resp.StatusCode, wantStatus)
}
}
// 两条 Times(1) 规则都已消费,IsDone 可作为规则耗尽的辅助判断。
if !gock.IsDone() {
t.Fatal("仍有未消费的 Gock 规则")
}
}
如果第一次请求返回 200,通常先检查规则声明顺序和是否有其他更宽泛的规则抢先匹配,而不是先修改 JSON。Gock 的文档还建议把更具体的规则放在更宽泛的规则之前,避免通用匹配条件提前截获请求。
连续响应排查时要看哪几层
| 排查层 | 要确认的内容 | 常见修复 |
|---|---|---|
| 请求条件 | 方法、主机、路径和参数是否真的相同 | 把额外的 MatchParam 或请求体条件逐项对齐 |
| 规则顺序 | 是否有通用规则在前面 | 先声明更具体的规则,再声明通用规则 |
| 次数控制 | Times(n) 是否覆盖实际调用次数 | 按调用契约设置次数,不用无限 Persist 冒充重试次数 |
| 响应清理 | 每轮响应体是否关闭 | 解码后关闭 Body,错误路径也释放资源 |
“同一路径不同响应”只解决规则层的顺序,不会自动替你实现重试循环。真实代码是否会发出第二次请求,仍由调用方的重试策略决定;如果只发出一次请求,第二条规则会保持未消费状态。
Times、IsDone 和 OffAll 不是一回事
Times(n) 是单条请求模拟的剩余次数设置;IsDone() 用来辅助判断当前注册的模拟是否都已完成;OffAll() 则负责关闭默认拦截、清空规则,并清理未匹配请求记录。测试结束时用 t.Cleanup 调用清理函数,可以避免前一个场景的规则影响后续测试。

如果你需要同一个响应持续服务多次,可以考虑 Persist();但它表达的是长期有效规则,不再是“第一次失败、第二次成功”这种有界序列。序列测试更适合给每个响应单独写规则,并用 Times(1) 把意图固定下来。
写重试模拟前的检查清单
先确认所有规则的请求条件是否足够具体,再确认声明顺序是否和期望的响应序列一致;然后用 Times 显式写出每条规则允许消费的次数。最后检查真实请求是否真的会重试、响应体是否关闭,以及测试结束时是否清理 Gock 状态。
同一路径的两条规则可以都不写 Times 吗?
可以,Gock 新建规则的默认计数是一次;不过写出 Times(1) 更容易表达序列意图,也便于读者检查调用次数。
第二条规则没有被消费说明什么?
通常说明调用方没有发出第二次请求,或者第一条规则没有按预期被消费。先看实际请求次数和匹配条件,再判断是否需要调整重试逻辑。
能不能用 Persist 返回多个不同响应?
不适合。Persist 让同一条规则持续有效,不能表达有限的响应序列;要模拟不同阶段的结果,应使用多条同条件规则和明确的次数。
Go Gock 怎样为自定义 http.Client 安装拦截器
- 上一篇
- Go Gock 怎样为自定义 http.Client 安装拦截器
- 下一篇
- Go SQLX 怎样把命名参数与 IN 列表展开组合起来
-
- Golang · Go教程 | 23分钟前 |
- Go Flock 怎样用 TryLock 实现非阻塞进程互斥
- 317浏览 收藏
-
- Golang · Go教程 | 24分钟前 |
- Go Flock 怎样用上下文超时等待文件锁
- 113浏览 收藏
-
- Golang · Go教程 | 26分钟前 |
- Go CEL 怎样限制表达式求值的成本预算
- 419浏览 收藏
-
- Golang · Go教程 | 27分钟前 |
- Go CEL 怎样用 PartialVars 保留尚未提供的输入
- 112浏览 收藏
-
- Golang · Go教程 | 29分钟前 |
- Go CEL 怎样声明输入变量并编译筛选表达式
- 394浏览 收藏
-
- Golang · Go教程 | 31分钟前 |
- Go Expr 怎样限制表达式最终必须返回布尔值
- 479浏览 收藏
-
- Golang · Go教程 | 35分钟前 |
- Go Expr 怎样预编译表达式并复用程序对象
- 204浏览 收藏
-
- Golang · Go教程 | 36分钟前 |
- Go Expr 怎样用 Env 为表达式声明结构化输入
- 357浏览 收藏
-
- Golang · Go教程 | 39分钟前 |
- Go Doublestar 怎样用 WithNoFollow 限制符号链接遍历
- 102浏览 收藏
-
- Golang · Go教程 | 39分钟前 | Go 文件遍历 io/fs Doublestar GlobWalk
- Go Doublestar 怎样用 GlobWalk 边遍历边处理匹配项
- 422浏览 收藏
-
- Golang · Go教程 | 42分钟前 |
- Go Doublestar 怎样只匹配指定目录下的多层文件
- 331浏览 收藏
-
- Golang · Go教程 | 43分钟前 |
- Go Pond 怎样为子池划分父池的并发额度
- 241浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 773次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 770次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 852次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 821次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 651次使用
-
- 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浏览

