第4章:压测脚本编写——HTTP请求参数化、CSV数据驱动、正则表达式提取器、JSON提取器实战
脚本编写这事,说难不难,说简单也不简单。我见过太多人把压测脚本写成「死脚本」——换一组数据就得改代码,换个接口就得重写。这哪叫压测?这叫手工活。
真正的压测脚本,得能自动适配数据、动态提取关联。今天我们就来把这几个硬骨头啃下来。
核心要点:参数化解决数据多样性,提取器解决接口依赖。两者结合,脚本才能「活」起来。
4.1 HTTP请求参数化——让脚本不再「死板」
参数化说白了,就是把脚本里的固定值变成变量。你想想看,如果每次请求都用同一个用户名、同一个商品ID,那测出来的吞吐量有什么参考价值?
JMeter里参数化的方式有好几种,我个人最常用的是用户自定义变量和CSV数据文件。前者适合少量固定参数,后者适合大批量数据驱动。
4.1.1 用户自定义变量
适合放一些全局配置,比如服务器地址、端口号、公共参数。操作很简单:
- 右键线程组 → 添加 → 配置元件 → 用户定义的变量
- 填写变量名和值,比如
base_url=http://api.example.com - 在HTTP请求里用
${base_url}引用
嗯,这里要注意:变量名别用中文,也别带特殊符号。我在项目中遇到过有人用 ${用户ID},结果跑的时候JMeter直接报错——变量名解析失败。
4.1.2 函数助手生成随机参数
有时候你不需要真实数据,只要随机值就行。JMeter的函数助手能帮上大忙。
比如生成随机手机号:
${__Random(13800000000,13999999999,phone)}
生成随机字符串:
${__RandomString(8,abcdefghijklmnopqrstuvwxyz,rand_str)}
这些函数在选项 → 函数助手对话框里都能找到,选好参数点生成,它会自动帮你拼好表达式。
小技巧:函数助手的表达式可以直接复制到脚本里。我习惯先在函数助手里测试一遍,确认能生成正确值,再贴到HTTP请求里。
4.2 CSV数据驱动——批量数据怎么喂?
真实场景下,压测需要成百上千条不同数据。一条条手写?不现实。这时候CSV数据文件就是最好的选择。
我曾经帮一个电商团队做压测,他们需要模拟10000个用户同时登录。每个用户的账号密码都不一样。用CSV驱动,一个文件搞定。
4.2.1 准备CSV文件
格式很简单,第一行是变量名,后面每行是一条数据:
username,password,user_id
test001,abc123,1001
test002,def456,1002
test003,ghi789,1003
注意:文件编码一定要是UTF-8,别用记事本默认的ANSI。我踩过这个坑——压测跑到一半,中文参数全变成乱码,排查了半天才发现是编码问题。
4.2.2 配置CSV数据文件元件
添加步骤:线程组 → 添加 → 配置元件 → CSV数据文件设置。
关键配置项:
| 配置项 | 推荐值 | 说明 |
|---|---|---|
| 文件名 | data/users.csv | 建议用相对路径,方便迁移 |
| 文件编码 | UTF-8 | 避免中文乱码 |
| 变量名称 | username,password,user_id | 与CSV第一行对应 |
| 分隔符 | , | 默认逗号,别乱改 |
| 遇到文件结束符 | 循环 / 停止线程 | 看需求,循环适合持续压测 |
| 线程共享模式 | 所有线程 | 每个线程取不同行 |
避坑指南:「遇到文件结束符」选「停止线程」时,如果数据行数少于线程数,后面的线程会直接报错。我曾经因为这个原因,压测只跑了60%的线程就停了,白白浪费了半天时间。建议选「循环」,或者确保数据量足够。
4.2.3 在脚本中引用CSV变量
配置好之后,直接在HTTP请求里用 ${变量名} 引用就行:
POST /api/login
参数: username=${username}, password=${password}
每个线程会从CSV文件里取一行数据,互不干扰。这就是数据驱动的核心——脚本不变,数据变。
4.3 正则表达式提取器——从响应里「捞」数据
接口之间经常有依赖关系。比如登录后拿到token,才能调用其他接口。这时候就需要从上一个请求的响应里提取数据。
正则表达式提取器,就是干这个活的。
4.3.1 什么时候用正则?
我个人习惯:响应格式是非结构化文本(HTML、纯文本、自定义协议)时,用正则。如果是JSON,我优先用JSON提取器,后面会讲。
4.3.2 配置步骤
添加位置:右键HTTP请求 → 添加 → 后置处理器 → 正则表达式提取器。
举个例子,登录接口返回的HTML里有一段:
<input type="hidden" name="token" value="a1b2c3d4e5f6" />
配置如下:
| 配置项 | 填写内容 | 说明 |
|---|---|---|
| 引用名称 | token | 后续用 ${token} 引用 |
| 正则表达式 | name="token" value="([^"]+)" | 括号里是要提取的内容 |
| 模板 | $1$ | 取第一个括号匹配的值 |
| 匹配数字 | 1 | 取第一个匹配结果 |
| 缺省值 | NOT_FOUND | 没匹配到时用这个 |
提取成功后,后续接口直接用 ${token} 就能拿到值。
调试技巧:加一个「调试取样器」或「查看结果树」,能看到提取出来的变量值。我每次写正则都会先跑一遍确认,避免正则写错了还傻傻往下跑。
4.3.3 正则写不对怎么办?
这是新手最容易卡住的地方。我的建议是:
- 先用在线正则工具(比如 regex101)测试
- 把响应内容复制出来,对着写正则
- 注意转义:
.要写成\.,"要写成\"
我曾经帮一个团队排查问题,他们提取token的正则写成了 token=(.*),结果匹配到了整个页面里所有带token的地方。最后提取出来的值乱七八糟。正确的写法应该是 token=([a-z0-9]+),精确匹配。
4.4 JSON提取器——处理JSON响应的利器
现在大部分接口返回的都是JSON格式。用正则去解析JSON,说实话有点「杀鸡用牛刀」。JMeter专门提供了JSON提取器,用JSON Path语法,简洁又精准。
4.4.1 JSON Path基础语法
先看一个典型的JSON响应:
{
"code": 0,
"data": {
"user_id": 1001,
"token": "abc123xyz",
"roles": ["admin", "editor"]
},
"message": "success"
}
JSON Path表达式:
| 目标 | JSON Path | 结果 |
|---|---|---|
| 取token | $.data.token | abc123xyz |
| 取user_id | $.data.user_id | 1001 |
| 取第一个角色 | $.data.roles[0] | admin |
| 取所有角色 | $.data.roles[*] | ["admin","editor"] |
4.4.2 配置JSON提取器
添加位置:右键HTTP请求 → 添加 → 后置处理器 → JSON提取器。
配置示例:
变量名: token
JSON Path表达式: $.data.token
匹配数字: 1
缺省值: NOT_FOUND
配置好之后,后续接口用 ${token} 就能拿到这个动态值。
为什么推荐JSON提取器?因为JSON Path比正则更直观,可读性更好。你想想看,$.data.token 一眼就知道取的是什么,而正则 "token":"([^"]+)" 还得琢磨半天。
4.4.3 实战:登录→下单的完整链路
把前面学的串起来,写一个完整的压测脚本:
- CSV数据驱动:从文件读取用户名、密码、商品ID
- 登录请求:用CSV里的账号密码登录
- JSON提取器:从登录响应里提取token和user_id
- 下单请求:用提取到的token做鉴权,用CSV里的商品ID下单
脚本结构大概是这样:
线程组
├── CSV数据文件设置 (读取账号、商品数据)
├── HTTP请求:登录
│ └── JSON提取器 (提取 token, user_id)
├── HTTP请求:下单
│ └── 参数: token=${token}, user_id=${user_id}, product_id=${product_id}
这样一套下来,脚本就能模拟不同用户、不同商品的真实操作。吞吐量测试的数据基础就有了。
注意:提取器要放在被提取请求的子节点下,别放错位置。我见过有人把提取器放在线程组下面,结果提取到的永远是上一次请求的值,数据全乱套了。
4.5 本章知识体系总览
下面这张图,把本章的核心知识点串起来了。建议你保存下来,写脚本的时候对照着看。
写到这里,我想强调一点:参数化和提取器不是孤立的。CSV负责喂数据,提取器负责传数据,两者配合才能写出真正能用的压测脚本。别只学一个就觉得自己会了,得串起来用。
好了,这一章的内容就这些。拿起JMeter,打开一个真实接口,从参数化开始练起。写坏了没关系,调试器会告诉你哪里错了。关键是动手。