首页
/
行业洞察
/
正文
INDUSTRY INSIGHT · 深度
Jmeter接口测试关联攻略:正则提取器、JSON提取器与跨线程组传参
📅 2026/10/21 18:41:37
✍️ 爱科研究院
👁 阅读 3,247
1. 搞懂测试关联为什么接口测试绕不开它如果你是最近才上手 Jmeter 做接口测试八成会在某一个时刻碰到同一个问题登录接口返回了一个 token下单接口必须带上这个 token不然服务器就甩给你一个“未认证”。或者是创建订单接口返回了一个订单号紧接着支付接口要用这个订单号你不把它取出来下一个请求就只能写死一个假数据一跑就挂。这个把上一个接口的响应数据动态地交给下一个接口去用的过程就是测试关联。说实话测试关联不算什么高级概念但它属于“不会就卡死、会了就顺手”的典型知识点。很多初学者一开始会用最笨的办法跑一遍登录从结果里手抄 token再填到下一个请求里。一次两次行但当你需要模拟几十个并发用户、每个人都带各自不同的 token 时手抄这条路完全走不通。Jmeter 里所有请求都是并发执行的每个虚拟用户的登录响应都不一样你不提前把关联写好性能测试就无从谈起。这篇文章我就从实际项目里用出来的经验出发把 Jmeter 里实现测试关联的几个主流方法掰开揉碎讲一遍正则提取器、JSON 提取器、跨线程组传参的套路以及我在真实项目中踩过的一堆坑。不管你是纯新手还是已经写过几个脚本的测试老手这篇文章都值得你花几分钟认真看一遍因为里面有些坑是我翻了半天文档才找到答案的。先说声这篇文章里涉及的操作实例我会用一套模拟的接口项目来讲解某平台以下称“模拟项目X”提供登录、用户信息查询、创建订单、支付订单四个接口。接口字段都是模拟的但逻辑和真实项目完全一致你照着同样的思路去套自己手头的接口就行。2. 关联方案选型正向思路与逆向避坑2.1 三种主流提取方式的适用边界Jmeter 实现关联归根结底就两步第一步把上一个请求的响应保存到一个变量里第二步在下一个请求里引用这个变量。不过“把响应保存到变量”这件事Jmeter 给了你好几种工具选错了工具后面就是无尽的烦恼。我先给一张总览表格你以后选方案时可以快速对照提取方式适用场景解析速度学习成本稳定性正则表达式提取器任意文本格式响应为 HTML、XML、纯文本、JSON 字符串等中等需要懂正则中JSON 提取器响应格式明确为 JSON快需要懂 JSONPath高边界提取器左右边界明确中间内容动态快低高CSS/JQuery 提取器响应为 HTML需要提取标签属性或内容快需要懂选择器中说句大实话我平时 90% 的场景只用到 JSON 提取器和正则提取器。边界提取器听起来很简单但遇到左右边界在文档中出现多次时就容易抓瞎反而不如正则灵活。CSS 提取器用的人比较少只处理 HTML 响应时可以考虑。选型有个核心原则JSON 响应优先用 JSON 提取器非 JSON 响应才用正则提取器。这个原则不是我定的而是实操教训换来的。JSON 解析是结构化的提取器会严格按照 JSONPath 语法取数据天然不会出现正则那种贪婪匹配、转义错误等一箩筐问题。而且 JSON 提取器的性能通常比正则好遇到响应体巨大时优势更明显。2.2 关联数据可能藏在哪些位置很多新手容易忽略一个问题关联数据不一定只存在于响应体中。我在项目里见过的几种常见位置是响应体Response Body最常见的 token、订单号、用户 ID 都在这里。响应头Response Headers有些项目喜欢把 token 放在响应头的 Authorization 或 Set-Cookie 字段里。曾经有一个 mock 项目sessionId 只在 Set-Cookie 里返回body 里压根没有。你只盯着 Body 看怎么都提取不到。响应状态行Response Status Line极少数时候接口会用状态码或状态行里的内容来传参。比如某个旧系统用 201 表示成功同时在响应头 Location 里返回新资源的 URL你要的 ID 可能就是 URL 最后一段。URL 重定向地址如果接口是重定向响应3xxLocation 字段里的参数经常被忽略。所以拿到一个新接口我建议你先用 Jmeter 跑一次打开“查看结果树”把响应体、响应头全展开看一眼。别急着写提取器先搞清楚数据到底在哪。这一步比选什么提取器都重要。3. 正则提取器实战从头到尾读透每一步3.1 正则提取器的界面配置拆解我们还是先看最通用的正则表达式提取器。它的配置面板长这样从“添加 → 后置处理器 → 正则表达式提取器”可以找到。看似格子不多但每个都有讲究Apply to默认是 Main sample only。如果这个请求下面挂了子请求比如页面加载了多个静态资源你需要根据实际情况决定是只管主样本还是管所有样本。接口测试一般都用默认值。要检查的响应字段Field to check核心选项。默认是 Body但前面说了如果数据在响应头就要选“响应头”或“信息头”。Jmeter 里英文界面是 Response Headers中文界面是信息头名字叫法不一样但指同一个东西。引用名称Reference Name这是你自己起的变量名后面用${变量名}来引用。注意这个名字不要和线程组里其他变量重名不然你会拿到一个被覆盖过的值排查到怀疑人生。正则表达式Regular Expression这是整个提取器的心脏后面单独讲。模板Template新建变量时如何从正则匹配结果里取值。配合正则里的捕获组使用$1$ 表示取第一个括号里的内容$2$ 取第二个。如果只想用匹配到的当前值不分组就直接写 $0$。匹配数字Match No.0 表示随机取一个匹配值1 表示取第一个2 表示取第二个。负数比较特殊表示使用所有匹配到的值。这个属性我们后面单独细说。默认值Default Value如果正则没有匹配到任何东西这个变量会被赋予默认值。我强烈建议这个值永远不要留空。最后一点要展开说。如果你不填默认值提取失败时 Jmeter 就会给变量一个空字符串。空字符串在后续请求里会导致什么不会直接报错而是发出一个字段缺失的请求服务器返回“参数错误”或“未认证”然后你又得回头查。但如果你填了默认值比如NOT_FOUND作用有两个第一你一眼就能在调试结果里看到这个变量没被匹配上第二部分校验场景下你可以直接用NOT_FOUND去断言判断这个接口是不是提取失败了。这个习惯帮我省了无数次排查时间。3.2 正则表达式的三个典型写法写正则表达式是很多人觉得难的地方但接口测试里需要的正则其实就那么几类。我总结了三个我在项目里反复用到的模板第一类提取 JSON 中的某个字符串值。响应{token:ABC123XYZ789,user_id:1001}你要拿 token正则这么写token:([^])这里([^])表示捕获一个不含双引号的连续字符串。[^]的意思是非双引号字符集表示一个或多个。这样写比token:(.*?)更严谨因为它强制要求取到的是非引号内容避免贪婪匹配引发的越界。第二类提取两段动态内容之间的数据。响应order_id20250113001/order_id正则order_id(.*?)/order_id.*?是非贪婪匹配表示尽可能少地匹配任意字符。如果你写成.*在页面存在两个order_id标签时就会出问题第一个匹配会把中间所有内容全部吞进去直到最后一个结束标签。这个坑我确实踩过排查了半天才发现是贪婪匹配把两个标签之间的东西全吃掉了。第三类提取请求路径中的动态片段。响应地址http://api.example-sim.com/order/88234/pay你要拿订单号 88234/order/(\d)/pay\d表示一位或多位数字专门用来提取纯数字内容。这里同样用到了捕获组模板填$1$。3.3 Match No. 和模板的配合逻辑正则的匹配结果可能不止一个。比如响应里有三个id标签你的正则需要能提取到指定的那一个。默认情况下Match No. 0Jmeter 会随机挑选其中一个结果。听起来好像没什么问题但随机意味着不可控。假如你后续断言期望先处理第一个 ID结果随机到了第三个测试就会产生偶发性的失败特别难排查。所以我的建议是需要取第几个就显式填写数字 1、2、3。如果接口返回的是一个列表你希望后续循环分别处理每一条数据那就把 Match No. 填为 -1。这时 Jmeter 会创建一个后缀_matchNr的变量来记录匹配总数同时生成多个变量比如var_1、var_2、var_3。你可以在循环控制器里配合使用。模板的作用也不止一种。假设你的正则写了两个捕获组模板填$1$-p0$2$这种组合也行Jmeter 会按模板拼接出一个新字符串。这个特性在做 URL 拼接时挺实用两段数据合并成一个变量省一次手动拼接。3.4 正则提取器效率优化与防坑正则写多了性能也是要关注的。虽然接口测试脚本通常不需要极致的解析速度但压测场景很多人直接就拿 Jmeter 脚本去跑性能测试。这时候响应体可能是个几千行的大 JSON一条写得很烂的正则比如大量使用.*会显着拖慢吞吐量。我自己总结了几条正则优化建议尽量用字符集代替点号。[^]比.*?更快、更安全。不要用.*开头除非确实不知道前缀是什么。正则引擎的贪婪回溯会消耗大量 CPU。固定前缀 .*? 固定后缀这种组合最好。如果一条正则特别复杂拆成多条后置处理器依次提取反而容易维护。另外提醒一句在调试正则时建议直接先把正则表达式提取器加上跑一次请求然后用“调试取样器”Debug Sampler配合“查看结果树”在响应里能看到所有变量的值。这个调试器比我手写 BeanShell 打印变量方便得多强烈安利。4. JSON 提取器与更高阶的数据处理4.1 JSONPath 的核心语法与记忆方法JSON 提取器的面板比正则提取器简单多了引用名称、JSONPath 表达式、默认值、匹配数字。真正花功夫的是 JSONPath 语法。不过别怕JSONPath 和 XPath 很像核心就几条规则。假设响应长这样{ code: 0, data: { token: EYJ123, user_info: { id: 1001, name: 张三 }, order_list: [ {order_id: A001, amount: 99.5}, {order_id: A002, amount: 150.0} ] } }JSONPath 取值的几个写法$.data.token取到EYJ123$表示根对象后面的点号表示一层层往下。$.data.user_info.id取到数字1001。$.data.order_list[0].order_id取到A001注意下标从 0 开始。$.data.order_list[*].order_id取到所有订单号列表。$.data.order_list[?(.amount 100)].order_id取到金额大于 100 的订单的 ID这是带过滤条件的写法虽然用得少但掌握后很省事。记不住 JSONPath 怎么办我的经验是在 JMeter 界面里用“JSON 提取器”面板旁边那个“测试”按钮写完表达式直接点一下就能看匹配结果不用反复跑请求。这个按钮在 Jmeter 5.x 版本里一直都有很多人没注意到实测很顶。4.2 JSON 提取器与正则提取器的运行时机使用 JSON 提取器有一个隐性前提请求的响应必须是合法 JSON。如果你的响应其实是 JSON 字符串嵌套在某个变量里比如有些封装会把 JSON 当字符串返回那么 JSON 提取器会报错或取不到值。另外要注意后置处理器的运行顺序。Jmeter 的后置处理器默认是顺序执行的。如果你在一个取样器下面挂了多个提取器它们会按从上到下的顺序跑。假设你用第一个正则提取了原始 JSON再用 JSON 提取器从这个 JSON 字符串里取内层字段那第一个提取器的变量必须定义在第二个提取器使用之前。不少同事栽过这个跟头在同一个取样器下加了两个提取器顺序反了结果第二个永远是空值。4.3 用 BeanShell 与 JSR223 补充复杂逻辑如果只是单纯提取一个字段JSON 提取器足够。但有些项目比较变态需要处理时间戳、拼接签名或者做多次数据转换这时候纯配置方式就捉襟见肘了。我常用 JSR223 取样器配合 Groovy 语言处理这些复杂场景。我举个典型场景登录接口返回的 token 可能是 JWT 格式中间段的 playload 是 Base64 编码的 JSON你需要解析出里面的用户角色再传给下一个接口。这种逻辑用提取器完全做不了只能在 JSR223 里写 Groovy 脚本来解码。写这类脚本时注意 Jmeter 提供了两个内置变量vars用于读写当前线程组的变量prev用于访问前一个取样器的结果。常见的一段代码长这样// 从上一个取样器的响应中获取数据并保存为新变量 String response prev.getResponseDataAsString(); // 这里可以解析 JSON 或者截取字符串 def json new groovy.json.JsonSlurper().parseText(response); String userId json.data.user_id; vars.put(userIdFromGroovy, userId);关键在于Groovy 脚本的执行效率远高于 BeanShell。Jmeter 官方文档也明确推荐在高并发场景下用 JSR223 Groovy而不是 BeanShell。所以我自己的项目里能不用 BeanShell 就不用。5. 从登录到支付完整串联一个接口关联实战案例5.1 接口背景与关联点分析纸上谈兵半天来做一个完整的模拟项目实战。模拟项目X提供四个接口登录接口POST /auth/login请求体为用户名和密码响应返回token和refresh_token。用户信息接口GET /user/info请求头需要携带登录拿到的token。创建订单接口POST /order/create请求体需要用户 ID响应返回order_id。支付订单接口POST /order/pay请求体需要order_id响应返回支付结果。正常情况下四个接口在业务上是一条链需要先登录拿到 token然后查用户信息拿到 user_id再创建订单拿到 order_id最后用 order_id 去支付。我在 Jmeter 里会新建一个线程组四个 HTTP 请求依次排列每个请求下面挂对应的提取器。这里最容易踩的坑是线程组策略默认情况下线程组里的多个取样器是按顺序执行的这没问题。但如果你开了“独立运行每个线程组”或者用了插件控制执行顺序关联就会断掉因为下一个请求的变量还没生成。5.2 第一步登录接口与 token 提取登录请求配置完成后给登录请求添加一个“正则表达式提取器”或“JSON 提取器”。因为登录返回的是 JSON 格式我选择 JSON 提取器引用名称loginTokenJSONPath 表达式$.data.token默认值NOT_FOUND跑一次登录请求打开“查看结果树”确认响应里存在data.token字段。然后在下一个请求的 HTTP Header 管理器里添加一个请求头Authorization: Bearer ${loginToken}注意这里的${loginToken}是 Jmeter 的变量引用语法。Jmeter 在运行时会把整个字符串中的${变量名}替换成变量的实际值。我见过新手在这里犯错误把${loginToken}写进了请求体请求体渲染时变成了字面量服务器就返回 token 无效。这部分其实很隐秘因为你点“查看结果树”时看到发送的报文里变量没有展开但有时候 Jmeter 的变量显示是有延迟的建议直接开“调试取样器”确认。5.3 第二步跨线程组传递数据的思路真实的项目中登录往往是一个线程组里的公共操作业务操作在另一个线程组。比如你压测时一个线程组专门负责登录并发另一个线程组负责下单业务并发这两个线程组之间的变量是不互通的。Jmeter 的变量作用域是这样的同一个线程组内后置处理器创建的变量默认只能在该线程组内可见。不同线程组之间默认是不可见的。那怎么让登录线程组里拿到的 token 传给业务线程组呢我有三种常用方案按推荐程度排序方案一使用属性props传递。Jmeter 的 props 是全局性的所有线程组都能访问。加一个 BeanShell 后置处理器或 JSR223 后置处理器props.put(globalToken, vars.get(loginToken));然后在另一个线程组里通过 JSR223 前置处理器读取String gToken props.get(globalToken); vars.put(loginToken, gToken);或者直接在请求头里使用${__P(globalToken)}引用属性。这里__P是 Jmeter 内置的函数专门读取全局属性。方案二使用 CSV 数据文件。登录线程组将 token 写入一个临时 CSV 文件业务线程组用 CSV 数据文件配置元件读取。这种方式适合需要大量数据、且要保留每个虚拟用户独立 token 的场景。缺点是文件 IO 会影响性能压测建议慎用。方案三把请求全部放在一个线程组里用逻辑控制器控制顺序。这最简单但灵活性差。最稳的个人建议能用单线程组解决的就在单线程组里完成主线程组业务线程组之间要传公共数据用 props 方案。5.4 第三步动态请求体与数据验证创建订单接口需要用户 ID。用户信息接口返回的是一位用户的 ID在 Jmeter 里你添加一个 JSON 提取器引用名称userId表达式$.data.user_info.id。然后创建订单请求体可以直接写成{ user_id: ${userId}, goods_id: 101, quantity: 2 }这里不需要双引号因为 user_id 是数字类型。如果服务端要求字符串你就写成user_id: ${userId}注意引号别漏不然 JSON 语法就错了。有些同学会问如果提取到的 user_id 是在某个范围内或者要做参数化组合怎么办这时我会用${__V()}或${__evalVar()}这类函数做变量嵌套。举个例子你需要把两个变量拼接${__V(userId_orderId)}这个__V函数会用括号里的内容作为变量名再去读取对应变量的值。嵌套变量的场景虽然不多但一旦遇到就会特别感谢有这个函数。响应数据验证方面我强烈建议给每次提取都做好断言。最常见的是在请求下加“响应断言”检查响应文本是否包含某个关键标识。比如支付请求返回{result: success}就断言响应文本包含success。这个断言能让你在逻辑断链时立刻定位到哪一步出了问题而不是傻傻地看整个链路黑盒运行。5.5 顺带说下循环控制器与批量数据关联在接口测试里经常需要对一批订单号逐个执行支付操作。这时我会用到“循环控制器”。在循环控制器里放一个支付请求循环次数填为绑定的变量比如 ${orderCount}。关键点如果订单号是列表提取器收到多个值后需要在循环内用变量动态引用。比如 JSON 提取器设置了匹配数字 -1生成了orderList_1、orderList_2等变量。循环控制器里用${__V(orderList_${i})}来动态取值其中i是循环计数变量。这段逻辑第一次看可能会绕建议找一个实际接口练一练理解了之后就会觉得非常好用。6. 常见问题与排查技巧实录6.1 提取不到值按这个顺序排查每次听到“我写了提取器但变量是空的”这种问题我心里都有一套固定排查顺序分享给你先用“查看结果树”确认该取样器的响应内容非空。如果响应本来就是空的那再怎么写提取器也没用。确认提取器挂在哪个取样器下面。提取器是后置处理器必须挂在“产生响应”的那个取样器下面不能挂在 Timer 或 HTTP Header 管理器下面。这个低级错误其实很常见。确认提取器中的“要检查的响应字段”是否选对。响应内容在 Body 里就选 Body在响应头里就选响应头。确认正则或 JSONPath 表达式本身没有问题。把表达式直接在提取器面板的“测试”按钮里跑一遍能立即看到结果这是一种非常直观的验证方式。检查引用名称是否与已有变量冲突。Jmeter 的变量系统在重复赋值时不会给你任何警告你只能通过 Debug 取样器看当前所有变量。确认该取样器之前是否有断言失败导致响应字段被置为空。有些断言在失败后会让后续取样器中断执行。6.2 变量在下一个请求里没生效作用域惹的祸有一个问题特别有代表性Session Id 是在登录取样器的响应头里提取的变量名sessionId。在接下来的 HTTP 请求里直接写 CookieJSESSIONID${sessionId}但测试结果显示发送出去的请求里这个 cookie 值是空的。这种问题十有八九就是作用域。Jmeter 的变量作用域默认是当前线程组当前取样器链但如果你的 HTTP 请求不在同一个线程组就看不到之前提取的变量。另一个常见误操作是两个 HTTP 请求虽然是同一个线程组但中间夹了一个“并行控制器”或“事务控制器”导致变量初始化顺序被打乱。解决方式也比较粗暴要么把提取器和引用提取器的请求放在同一个线性的取样器链里要么用 props 做全局变量跨线程组共享。6.3 中文乱码与编码问题接口返回的中文变成了\u5728\u7ebf\u65e5\u5fd7这种 Unicode 转义或者直接乱码通常在两种场合格外明显一是响应内容编码是 UTF-8 但 Jmeter 默认用 ISO-8859-1 解析二是接口返回的内容是 Gzip 压缩流需要先解压再提取。针对第一种情况在 HTTP 请求的“内容编码”一栏填上 UTF-8 基本可以解决。如果某些响应是 GB2312 编码则在 JSR223 里用prev.getResponseDataAsString()配合手动指定字符集读取更灵活。第二种情况的解法是在 HTTP 请求下添加一个“BeanShell 后置处理器”或“JSR223 后置处理器”先判断prev.getContentEncoding()再解压然后再做提取。我建议你平时多留意接口的 Content-Type 和 Content-Encoding 头部很多提取失败其实是编码问题伪装出来的。6.4 多个匹配时的必要策略正则提取器在遇到响应里出现多个相同结构时默认取随机一个容易导致测试不稳定。我在第 3.3 节提过 Match No. 的作用。这里再补充一个实战场景创建订单接口一次返回 10 个订单号后续要做轮询直到订单变为“已支付”。这种情况不适合在 Jmeter 里用一个变量解决而是要把订单号列表存下来配合 BeanShell 或 Groovy 做逻辑判断。我的做法是// 伪代码遍历订单号列表检查每个订单状态 String orderList vars.get(orderList_matchNr); for (int i 1; i Integer.parseInt(orderList); i) { String orderId vars.get(orderList_ i); // 发起查询请求判断状态 }这段代码用 JSR223 实现会很稳但注意不要在大并发下用过多 Groovy 做复杂 IO会影响压测结果。7. 最后聊一点个人经验做了这么久的接口测试我最大的感受是关联这个功能本身不难难的是对响应数据的敏感度。拿到一个接口先判断它依赖哪些数据、能提供哪些数据画一张简单的数据流转表再动手写脚本比上来就在 Jmeter 里堆提取器要高效得多。这也是老手和新手之间最明显的区别之一。如果你刚开始接触我建议你拿自己手头最常见的接口练手先跑通“登录 token 提取 → 下一个请求引用”这个闭环再逐步尝试跨线程组和循环处理。不要一上来就追求用 Groovy 处理一切复杂逻辑灯下黑的情况我见过太多了。至于将来这套思路完全可以直接平移到接口自动化平台或 CI 流水线里——只要你理解了“变量怎么来、变量怎么用、变量作用域有多大”这三个问题不管 Jmeter 未来怎么更新或者你切换到其他工具核心逻辑都不会变。希望这篇文章能让你少走一些弯路。如果实操中遇到问题欢迎在讨论区把你的请求结构描述出来大家互相参考一下。
📌 标签:
工业官网
设计趋势
AI 建站
SEO
获取完整报告 →
RELATED ARTICLES
推荐阅读
2026/10/21 18:41:37
AI成为标配后,知识服务者如何构建人机协作新竞争力
2026/10/21 18:41:37
区块链项目商业计划书技术评估与最小可验证版本开发指南
2026/10/21 18:41:37
STM32两轮自平衡小车实战:从姿态解算到PID调参与硬件细节
2026/10/21 19:37:56
DeepSeek-V3技术报告解读:从MoE架构到训练部署落地
2026/10/21 19:37:56
Python 字符串完全指南:从内存模型到编码正则的避坑手册
2026/10/21 19:37:56
贪心算法适用边界与经典案例详解:从理论到工程实践
2026/10/21 19:37:56
贪心算法核心性质与实战解析:从最优子结构到动态规划边界
2026/10/21 19:37:56
从废旧材料到个人艺术手作坊:artcraft改造实战指南
2026/10/21 19:32:55
Gazebo仿真从“看着像”到“真能用”:物理、惯性、噪声与性能调优实战
2026/10/21 0:01:44
ClickHouse实战:从列式存储到亿级数据秒级查询
2026/10/21 0:01:44
高效筛选arXiv机器学习论文:四步法实战指南
2026/10/21 0:01:44
Python爬取百度迁徙数据:接口签名、反爬与SQLite存储实战
2026/10/21 19:05:16
OpenResearch实战:Claude Code、Codex、OpenCode、Cursor 工作流搭建与故障排查
2026/10/21 14:47:26
知识管理核弹:用Obsidian构建第二大脑的工程化方案(TaoToken 统一 Key 接入版)
2026/10/21 19:05:04
金融AI落地指南:从调研报告到技术选型与工程实践
2026/10/20 2:24:03
我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
2026/10/20 2:23:57
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026/10/21 19:01:08
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)