4. 编写第一个压测脚本:HTTP请求配置、参数化(CSV/函数)、断言与监听器
好,到了真正动手的环节了。前面我们聊了环境搭建、聊了线程组,说白了都是在热身。现在我们要写第一个真正能跑的压测脚本。别紧张,其实就四个核心步骤:配请求、搞参数化、加断言、挂监听器。我带你走一遍,你跟着敲一遍,基本就通了。
4.1 HTTP请求配置:别小看这个“填表单”
在JMeter里添加一个HTTP请求,操作很简单:右键线程组 → Add → Sampler → HTTP Request。但配置起来,有几个坑我得提前跟你说。
核心配置项速查表
| 配置项 | 说明 | 我踩过的坑 |
|---|---|---|
| Protocol | http 或 https | https记得勾选“Use KeepAlive”,不然连接数飙升 |
| Server Name or IP | 目标域名或IP | 别带http://,只写域名 |
| Port Number | 默认80/443可不填 | 非标端口一定要写,我见过有人漏了端口压了一整天全失败 |
| Method | GET/POST/PUT等 | POST请求别忘了在Body Data里写参数 |
| Path | 接口路径 | 以/开头,比如 /api/login |
| Parameters / Body Data | 请求参数 | GET用Parameters,POST用Body Data |
举个例子,我要压一个登录接口:
协议:https
服务器:api.example.com
端口:443
方法:POST
路径:/v1/login
Body Data:{"username":"test","password":"123456"}
嗯,这里要注意:如果你用POST但参数填在Parameters里,服务端大概率收不到。我刚开始就犯过这个错,查了半天还以为代码写错了。
4.2 参数化:让脚本“活”起来
你想想看,如果1000个线程都用同一个账号压登录,那测出来的是缓存性能,不是真实吞吐。所以我们需要参数化——让每个虚拟用户用不同的数据。
JMeter里常用的参数化方式有两种:CSV数据文件和函数助手。我个人习惯是:数据量大用CSV,数据量小或者临时用用函数。
4.2.1 CSV参数化
步骤很简单:
- 准备一个CSV文件,比如
users.csv,内容如下:
username,password
user1,pass1
user2,pass2
user3,pass3
- 在线程组下添加 CSV Data Set Config:
Filename: /path/to/users.csv
Variable Names: username,password
Delimiter: ,
Recycle on EOF: False
Stop thread on EOF: True
- 在HTTP请求里引用变量:
Body Data:{"username":"${username}","password":"${password}"}
小技巧:CSV文件路径建议用路径,或者放在JMeter的bin目录下用相对路径。我遇到过用相对路径但工作目录不对导致文件找不到的情况,排查了半小时。
4.2.2 函数参数化
有时候你不想准备文件,就想随机生成点数据。JMeter的函数助手能帮你:
${__Random(1,100)}— 生成1到100的随机数${__time(yyyy-MM-dd)}— 生成当前日期${__UUID()}— 生成唯一ID
举个例子,压测注册接口时,我需要每个用户邮箱不重复:
Body Data:{
"email": "test_${__time()}_${__Random(1000,9999)}@example.com",
"password": "123456"
}
这样每次请求的邮箱都不一样。说白了,函数适合临时造数据,CSV适合用真实数据。
4.3 断言:别让错误数据骗了你
压测时最怕什么?最怕接口返回了200,但内容是“系统繁忙”或者“参数错误”。如果你不看响应体,光看TPS,那数据全是假的。
所以我们要加断言。JMeter里最常用的是响应断言(Response Assertion)。
添加方式:右键HTTP请求 → Add → Assertions → Response Assertion。
配置示例:
Apply to: Main sample only
Field to Test: Text Response
Pattern Matching Rules: Contains
Patterns to Test: "success"
这样,只有响应体里包含“success”的请求才算通过。否则JMeter会标记为失败,在聚合报告里显示为错误。
我曾经踩过的坑:有一次压测,我断言了“200 OK”,结果服务端所有请求都返回了200,但实际业务逻辑全失败了。从那以后,我坚持断言业务关键词,而不是HTTP状态码。
除了响应断言,还有JSON断言、大小断言等。我个人建议:刚开始用响应断言就够了,等后面做复杂业务再上JSON断言。
4.4 监听器:把数据“画”出来
脚本跑完了,怎么看结果?监听器就是干这个的。JMeter里监听器种类很多,但刚开始你只需要记住三个:
| 监听器 | 用途 | 什么时候用 |
|---|---|---|
| 查看结果树 | 看单个请求的详情 | 调试脚本时必加 |
| 聚合报告 | 看整体统计数据 | 正式压测时必加 |
| 图形结果 | 看趋势变化 | 观察性能波动时用 |
添加方式:右键线程组 → Add → Listener → 选择对应的监听器。
注意:正式压测时,记得禁用“查看结果树”。为什么?因为它会把每个请求的响应体都存到内存里,压个几千线程,内存直接爆掉。我见过有人压了10分钟,JMeter直接OOM崩溃,白跑了。
4.5 完整脚本结构图
下面这张图,把上面讲的四个部分串起来了。你照着这个结构搭,基本不会错。
4.6 完整脚本示例
好了,我们把上面所有东西拼起来,就是一个完整的压测脚本了。下面是一个登录接口的完整示例:
线程组
├── CSV Data Set Config
│ ├── Filename: /data/users.csv
│ ├── Variable Names: username,password
│ └── ...
├── HTTP Request
│ ├── Server: api.example.com
│ ├── Method: POST
│ ├── Path: /v1/login
│ ├── Body Data: {"username":"${username}","password":"${password}"}
│ └── ...
├── Response Assertion
│ ├── Field: Text Response
│ ├── Pattern: ""
│ └── ...
└── Listeners
├── View Results Tree (调试时开启)
├── Aggregate Report
└── Graph Results
我的习惯:每次新建脚本,我都会先加一个“查看结果树”跑一遍单线程,确认请求和断言都对了,再改成多线程正式压。这一步能省下大量排错时间。
嗯,到这里,你的第一个压测脚本就写完了。配置了HTTP请求、做了参数化、加了断言、挂了监听器。说白了,这就是压测脚本的“四件套”,后面所有复杂的场景都是在这个基础上叠加的。