第4章:压测脚本编写——HTTP请求参数化、CSV数据驱动、正则表达式提取器、JSON提取器实战

脚本编写这事,说难不难,说简单也不简单。我见过太多人把压测脚本写成「死脚本」——换一组数据就得改代码,换个接口就得重写。这哪叫压测?这叫手工活。

真正的压测脚本,得能自动适配数据、动态提取关联。今天我们就来把这几个硬骨头啃下来。

核心要点:参数化解决数据多样性,提取器解决接口依赖。两者结合,脚本才能「活」起来。

4.1 HTTP请求参数化——让脚本不再「死板」

参数化说白了,就是把脚本里的固定值变成变量。你想想看,如果每次请求都用同一个用户名、同一个商品ID,那测出来的吞吐量有什么参考价值?

JMeter里参数化的方式有好几种,我个人最常用的是用户自定义变量和CSV数据文件。前者适合少量固定参数,后者适合大批量数据驱动。

4.1.1 用户自定义变量

适合放一些全局配置,比如服务器地址、端口号、公共参数。操作很简单:

  1. 右键线程组 → 添加 → 配置元件 → 用户定义的变量
  2. 填写变量名和值,比如 base_url = http://api.example.com
  3. 在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 实战:登录→下单的完整链路

把前面学的串起来,写一个完整的压测脚本:

  1. CSV数据驱动:从文件读取用户名、密码、商品ID
  2. 登录请求:用CSV里的账号密码登录
  3. JSON提取器:从登录响应里提取token和user_id
  4. 下单请求:用提取到的token做鉴权,用CSV里的商品ID下单

脚本结构大概是这样:

线程组
├── CSV数据文件设置 (读取账号、商品数据)
├── HTTP请求:登录
│   └── JSON提取器 (提取 token, user_id)
├── HTTP请求:下单
│   └── 参数: token=${token}, user_id=${user_id}, product_id=${product_id}

这样一套下来,脚本就能模拟不同用户、不同商品的真实操作。吞吐量测试的数据基础就有了。

注意:提取器要放在被提取请求的子节点下,别放错位置。我见过有人把提取器放在线程组下面,结果提取到的永远是上一次请求的值,数据全乱套了。

4.5 本章知识体系总览

下面这张图,把本章的核心知识点串起来了。建议你保存下来,写脚本的时候对照着看。

压测脚本编写核心知识体系 压测脚本 参数化 用户自定义变量 函数助手(随机值) CSV数据文件驱动 数据提取器 正则表达式提取器 JSON提取器 实战链路:登录 → 提取 → 下单 CSV驱动不同用户 → JSON提取token → 动态下单 核心原则:脚本不变,数据变;请求解耦,提取器串联

写到这里,我想强调一点:参数化和提取器不是孤立的。CSV负责喂数据,提取器负责传数据,两者配合才能写出真正能用的压测脚本。别只学一个就觉得自己会了,得串起来用。

好了,这一章的内容就这些。拿起JMeter,打开一个真实接口,从参数化开始练起。写坏了没关系,调试器会告诉你哪里错了。关键是动手。