本文介绍在 jmeter 中使用 groovy 脚本动态解析未知结构的 json 响应,无需预定义字段即可完整提取所有路径式键名及其对应值,适用于设备列表、嵌套配置等灵活接口场景。
本文介绍在 jmeter 中使用 groovy 脚本动态解析未知结构的 json 响应,无需预定义字段即可完整提取所有路径式键名及其对应值,适用于设备列表、嵌套配置等灵活接口场景。
在性能测试中,常遇到返回结构动态、字段不固定的 JSON 接口(例如 IoT 设备列表、微服务聚合响应),此时无法使用 JMeter 内置的
JSON Extractor
(需提前指定 JSON Path)。此时,Groovy 是最可靠的选择——它能真正实现「无 schema 遍历」,不仅获取全路径键名(如 devices[0].attributes.name),还能同步捕获其最终值。
以下是一个增强版递归遍历脚本,可精准输出每个叶子节点的「完整路径 + 对应值」,并支持直接写入 JMeter 变量供后续请求复用:
✅
脚本优势说明:
✅ 真正区分「容器节点」与「叶子节点」:仅对字符串、数字、布尔、null 等基础类型输出键值,避免将 attributes 这类中间对象误作有效值;
✅ 完整保留数组索引路径(如 devices[24].attributes.name),确保路径可追溯、可复用;
✅ 自动调用 .toString() 处理 null 和基本类型,规避空指针异常;
✅ 将结果批量写入 vars(JMeter 变量上下文),支持在后续 HTTP 请求、JSR223 Sampler 或 BeanShell 中通过 ${json_key_0} 引用。
⚠️
注意事项:
请将此脚本放入
JSR223 PostProcessor
(作用域为对应 HTTP 请求),确保 prev 可正确访问前序响应;
若 JSON 体积极大(>10MB),建议添加深度限制或日志采样,避免内存溢出;
生产环境建议关闭 log.info 输出(或改为 log.debug),减少 I/O 开销;
如需按路径筛选(例如只取所有 *.name 字段),可在 allEntries 后追加 Groovy findAll{} 过滤逻辑。
掌握该方法后,你将彻底摆脱“字段未知就无法提取”的困境,让 JMeter 具备真正的 JSON 动态解析能力——无论接口如何演进,脚本始终健壮可用。
import groovy.json.JsonSlurper
def traverse = { tree, result = [], prefix = '' ->
switch (tree) {
case Map:
tree.each { k, v ->
def keyPath = prefix ? "${prefix}.${k}" : k
if (v instanceof Map || v instanceof Collection) {
// 非叶子节点:继续递归
traverse(v, result, keyPath)
} else {
// 叶子节点:记录路径和值(自动处理 null/基本类型)
result << ["key": keyPath, "value": v?.toString()]
}
}
return result
case Collection:
tree.eachWithIndex { item, idx ->
def indexedPath = "${prefix}[${idx}]"
if (item instanceof Map || item instanceof Collection) {
traverse(item, result, indexedPath)
} else {
result << ["key": indexedPath, "value": item?.toString()]
}
}
return result
default:
// 基础类型(String/Number/Boolean)或 null
if (prefix) {
result << ["key": prefix, "value": tree?.toString()]
}
return result
}
}
// 解析上一个请求的响应体
def json = new JsonSlurper().parseText(prev.getResponseDataAsString())
def allEntries = traverse(json)
// 【可选】打印全部键值对(调试用)
allEntries.each { entry ->
log.info("KEY: ${entry.key} → VALUE: ${entry.value}")
}
// 【关键】将结果存为 JMeter 变量,供后续使用(例如:vars.put("json_key_0", "devices[0].attributes.name"))
allEntries.eachWithIndex { entry, idx ->
vars.put("json_key_${idx}", entry.key)
vars.put("json_value_${idx}", entry.value)
}
log.info("共提取 ${allEntries.size()} 个键值对,已存入变量 json_key_* / json_value_*")