4. 编写第一个压测脚本:HTTP请求配置、参数化(CSV/函数)、断言与监听器

好,到了真正动手的环节了。前面我们聊了环境搭建、聊了线程组,说白了都是在热身。现在我们要写第一个真正能跑的压测脚本。别紧张,其实就四个核心步骤:配请求、搞参数化、加断言、挂监听器。我带你走一遍,你跟着敲一遍,基本就通了。

4.1 HTTP请求配置:别小看这个“填表单”

在JMeter里添加一个HTTP请求,操作很简单:右键线程组 → Add → Sampler → HTTP Request。但配置起来,有几个坑我得提前跟你说。

核心配置项速查表

配置项说明我踩过的坑
Protocolhttp 或 httpshttps记得勾选“Use KeepAlive”,不然连接数飙升
Server Name or IP目标域名或IP别带http://,只写域名
Port Number默认80/443可不填非标端口一定要写,我见过有人漏了端口压了一整天全失败
MethodGET/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参数化

步骤很简单:

  1. 准备一个CSV文件,比如 users.csv,内容如下:
username,password
user1,pass1
user2,pass2
user3,pass3
  1. 在线程组下添加 CSV Data Set Config:
Filename: /path/to/users.csv
Variable Names: username,password
Delimiter: ,
Recycle on EOF: False
Stop thread on EOF: True
  1. 在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 完整脚本结构图

下面这张图,把上面讲的四个部分串起来了。你照着这个结构搭,基本不会错。

第一个压测脚本结构图 线程组 CSV Data Set Config HTTP请求 函数参数化 响应断言 查看结果树 聚合报告 图形结果 ⚠️ 正式压测时,记得禁用“查看结果树” 它会缓存所有响应体,高并发下容易OOM 调试阶段开启,压测阶段关闭

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请求、做了参数化、加了断言、挂了监听器。说白了,这就是压测脚本的“四件套”,后面所有复杂的场景都是在这个基础上叠加的。