每次带新人做性能测试,我都会先问一句:你的压测脚本是怎么来的?十有八九的回答是“用 Jmeter 录的”。Jmeter 录制压测脚本确实快,浏览器点一遍,HTTP Sampler 就哗啦啦生成一堆,比手写省太多时间。但录制这件事,说简单也简单,说坑也多,尤其碰到 HTTPS、动态 Token、Cookie、文件上传、数据库参数化,录完只是第一步,回放能跑通、能压出有效数据,才算真正完成。常见录制方式我习惯分成四类:Jmeter 自带 HTTP(S) Test Script Recorder 代理录制、Badboy 录制后导入、浏览器扩展录制、Fiddler/Charles 抓包转 HAR 再导入。它们背后的原理都是抓请求,但适用场景、证书处理、后处理成本差别很大。下面按实战顺序拆开讲,从安装配置、代理设置、过滤规则、关联提取,到 CSV 参数化、JDBC Request 取值、BeanShell 断言、命令行压测和报告导出,尽量把踩过的坑一次说透。
1. 录制方式的整体选型与准备
1.1 四种录制方式适用场景对比
选录制方式,不要只看“哪个最方便”,要看项目类型、协议、团队习惯和后续维护成本。我通常先判断三件事:是不是 HTTP/HTTPS、有没有复杂动态参数、录制后是谁维护。如果是内部管理系统、传统 MVC 项目,Badboy 或 Jmeter 自带代理都能快速出活;如果是前后端分离、RESTful 接口、大量 JSON 交互,浏览器扩展或抓包工具更顺手;如果要做移动端 App 压测,Jmeter 自带代理和抓包工具是主流。
| 录制方式 | 核心原理 | 适合场景 | HTTPS 支持 | 主要优点 | 典型坑 |
|---|---|---|---|---|---|
| Jmeter 自带代理录制 | Jmeter 作为代理服务器转发请求并生成 Sampler | Web、移动端、需要精细过滤 | 需要信任 Jmeter 根证书 | 原生、可控、过滤强 | 证书配置繁琐,静态资源易混入 |
| Badboy 录制导入 | Badboy 内置浏览器录制并导出 JMX | 传统 Web、快速回归、老项目 | Badboy 内部处理 | 上手最快,导出直接 | 现代前端兼容差,动态请求易漏 |
| 浏览器扩展录制 | Chrome 扩展监听页面请求并导出 JMX/HAR | 前后端分离、RESTful、单页应用 | 浏览器层面处理 | 操作直观,前端视角清晰 | 扩展差异大,静态请求多 |
| 抓包工具辅助录制 | Fiddler/Charles 抓包导出 HAR 再转 JMX | 移动端、复杂 HTTPS、接口联调 | 需安装抓包根证书 | 请求细节全,便于分析 | 手动整理多,转换工具需验证 |
这张表不是让你死记,而是提醒自己:录制方式只是入口,真正决定效率的是后处理。Jmeter 自带代理录出来的脚本最“原生”,但需要处理证书和过滤;Badboy 最快,但遇到 Vue、React 这类单页应用容易只录到壳;浏览器扩展适合接口清晰的 RESTful 项目;抓包工具最灵活,但也最考验手工整理能力。
1.2 录制前环境准备与安装要点
不管你用哪种方式,Jmeter 安装配置都是第一步。Windows 上先装 JDK,Jmeter 5.x 通常要求 Java 8 或以上,我一般用 JDK 8 或 JDK 11,避免太新的 JDK 导致插件不兼容。Jmeter 安装包从 Apache Jmeter 官网下载,解压到非中文、非空格路径,比如D:\tools\apache-jmeter-5.6.3。然后配置JMETER_HOME,把%JMETER_HOME%\bin加到 Path,命令行敲jmeter -v能看到版本就说明安装配置成功。
第一次打开 Jmeter,界面字体太小可以调。在bin/jmeter.properties里改jmeter.hidpi.mode=true、jmeter.hidpi.scale.factor=1.5,或者启动时加-Jjmeter.hidpi.scale.factor=1.5。如果只是临时看,也可以在选项菜单里找外观设置,但改配置文件更稳。插件包安装靠 Plugins Manager,把jmeter-plugins-manager.jar放进lib/ext,重启后就能在选项里装插件。要做 MQTT 压测就装 MQTT 插件,要做 JDBC 压测就确认 MySQL 驱动放进lib。这些准备不做,后面录制再顺也会卡在回放阶段。
注意:Jmeter 安装路径不要带中文和空格,脚本文件、CSV 文件、结果文件也尽量用英文路径。很多“文件已经存在”“找不到 CSV”问题,最后都是路径惹的祸。
1.3 录制脚本与手工编写的边界
录制不是万能。HTTP/HTTPS 请求适合录,但 JDBC 请求、MQTT、WebSocket、gRPC、自定义 Java 协议,录制工具基本帮不上忙,还是得手工搭。我的习惯是:能录的接口先录,录完再手工补关联、断言、参数化;不能录的接口,根据抓包结果或接口文档手工建 Sampler。比如 RESTful 接口,录制出来可能是POST /api/order,但参数在 JSON Body 里,你要确认 Content-Type、Body Data、鉴权 Header 是否正确。再比如 MVC 项目常见的__RequestVerificationToken,录制会带上,但回放时如果不动态提取,就会报“未提供必要的防伪标记”。
所以录制前先想清楚:这次是要做接口功能回归,还是做高并发压测?功能回归可以保留较多请求;压测必须删掉登录后无关的查询、静态资源、埋点请求,只保留核心链路。录制出来的脚本如果包含几十个静态请求,压测时线程一多,压力全打在无关资源上,结果就没有参考意义。
2. Jmeter 自带代理录制:最稳的 HTTP/HTTPS 方案
2.1 测试计划与 HTTP(S) Test Script Recorder 配置
Jmeter 自带代理录制是我最推荐的入门方式,也是团队里最稳的方案。步骤不复杂:打开 Jmeter,新建测试计划,添加线程组,再添加HTTP(S) Test Script Recorder。在录制器里设置端口,默认 8888,如果被占用就换 8899。目标控制器选择“使用录制控制器”,Jmeter 会自动建一个Recording Controller,录下来的请求都放在里面。
关键在 URL Patterns。Include里填你要录的业务域名,比如.*example\.com.*,Exclude里排除静态资源:.*\.(js|css|png|jpg|gif|ico|woff|woff2|svg).*。如果你只想录某个路径,可以写.*example\.com/api/.*。分组方式建议选“每个请求放入一个新事务控制器”或“按请求分组”,这样录出来的结构清晰,后续删减方便。
启动录制器后,Jmeter 会在bin目录生成一个临时根证书。浏览器第一次通过代理访问 HTTPS 站点时,会提示证书不受信任。你需要把ApacheJMeterTemporaryRootCA.crt导入浏览器或系统信任库,否则 HTTPS 请求录不到,或者录出来全是握手失败。很多人说“Jmeter 录制 HTTPS 脚本录不到”,九成是证书没信任。
2.2 浏览器/移动端代理与 HTTPS 证书信任
浏览器端我优先用 Firefox,因为它的代理设置独立,不影响系统全局代理。设置手动代理:HTTP 代理127.0.0.1,端口8888,勾选“也为 HTTPS 使用此代理”。然后访问目标系统,正常操作,Jmeter 里就会看到请求不断出现。Chrome 现在也支持独立代理,但系统级代理有时会影响其他软件,所以我更倾向于 Firefox 或专用测试浏览器。
移动端录制更需要注意。手机和电脑连同一个局域网,手机 WiFi 设置里配置手动代理,主机填电脑 IP,端口填 8888。然后手机浏览器访问http://电脑IP:8888,下载 Jmeter 根证书并安装。Android 7 以后,用户证书默认不被 App 信任,如果被测 App 没有单独信任用户证书,HTTPS 请求可能抓不到。这时候可以用调试包,或者让开发在测试包中配置信任用户证书。iOS 安装证书后,还要在“关于本机-证书信任设置”里手动开启完全信任。
注意:只录制你自己有权限测试的系统。生产环境、第三方系统、涉及个人隐私的请求不要随意录制和保存。
2.3 过滤规则、Cookie 管理与请求清理
录制结束后第一件事不是直接压,而是清理。把图片、CSS、JS、字体、埋点、广告请求删掉。判断标准很简单:这个请求去掉后,业务流程还能不能走通?不能就保留,能就删。Jmeter 的HTTP Cookie Manager要加上,并勾选“每次迭代清除 Cookies”还是“保留”,取决于业务。如果压测模拟同一用户连续操作,可能保留 Cookie;如果每个线程模拟独立用户,通常需要清除或使用不同会话。
Cookie 设置常见问题:录制时带了JSESSIONID,回放时如果直接复用,多个线程会共享同一个会话,压测结果会失真。正确做法是用HTTP Cookie Manager自动管理,或者用正则提取登录后的 Cookie,再通过HTTP Header Manager传入。有些系统把 Token 放在 LocalStorage 里,Jmeter 看不到,需要从登录响应中提取 Token,再手动加到 Header。
2.4 录制后关联、参数化和断言补全
录制脚本最核心的后处理是关联。动态参数包括:登录 Token、Session、订单号、时间戳、签名、CSRF Token。提取方式有正则表达式提取器、JSON Extractor、XPath Extractor。JSON 接口优先用 JSON Extractor,比如$.data.token,提取到变量token,后续请求引用${token}。正则适合 HTML 或非标准 JSON。如果 Token 在响应头,用正则提取响应头。
参数化是压测脚本的灵魂。把用户名、密码、搜索关键字、订单 ID 放到 CSV 文件,用CSV Data Set Config读取。如果接口需要上传文件,勾选Use multipart/form-data,在 Files Upload 里填文件路径、参数名、MIME 类型。RESTful 接口的路径参数可以直接写在 Path 里,比如/api/user/${userId},查询参数放在 Parameters 里,JSON Body 放在 Body Data 里。BeanShell 断言可以校验响应是否包含成功标识,比简单响应断言灵活。比如登录后判断responseData是否包含"code":0,不包含就Failure=true。
3. Badboy 录制与导入:快速回归的老牌选择
3.1 Badboy 安装与录制流程
Badboy 是一个老牌录制工具,安装包很小,打开就是内置浏览器。输入目标 URL,点击红色录制按钮,然后在页面里操作,左侧会生成请求树,右侧显示页面。操作完成后停止录制,可以回放确认,再导出为 Jmeter JMX 文件。它的优势是安装快、上手快,不需要配代理和证书,适合传统 Web 系统、内部管理后台、老项目快速回归。
但 Badboy 对现代前端支持有限。Vue、React 这类单页应用,页面跳转不刷新,Badboy 可能只录到初始 HTML 和少量接口;WebSocket、SSE 更录不到。另外,Badboy 内置浏览器内核较旧,有些新站点直接打不开。所以我现在只在维护老项目时用它,新项目优先选 Jmeter 自带代理或浏览器扩展。
3.2 导出 JMX 与导入 Jmeter 要点
Badboy 导出 JMX 后,用 Jmeter 打开。先检查线程组、Sampler、Cookie Manager 是否完整。Badboy 通常会自带 Cookie 管理,但域名、端口、协议可能需要改。比如录制时是http://test.example.com:8080,压测环境换成http://perf.example.com,就要批量替换。可以用 Jmeter 的“查找替换”功能,也可以导出 JMX 后用文本编辑器替换,但改完一定要重新打开验证。
导入后重点看三处:请求头是否正确、参数是否完整、动态参数是否需要提取。Badboy 录制时把请求参数写死在 Sampler 里,回放一次可能成功,多线程并发就会因为订单号重复、Token 过期而失败。所以导入后必须补关联和参数化。如果只是做简单功能回归,Badboy 导出的脚本够用;如果做高并发压测,必须彻底改造。
3.3 常见兼容问题与修补策略
Badboy 常见问题包括:中文乱码、HTTPS 证书不受信任、AJAX 请求遗漏、上传文件失败。中文乱码一般是编码不一致,在 Jmeter 里把sampleresult.default.encoding=UTF-8写进jmeter.properties。HTTPS 录不到就换 Jmeter 自带代理。AJAX 遗漏可以结合 Fiddler 抓包,把漏掉的接口手工补进 Jmeter。上传文件失败要检查 multipart 边界和参数名,最好用 Jmeter 的 HTTP 请求重新实现上传。
我个人的经验是:Badboy 适合“录一遍,快速看请求结构”,不适合作为长期维护的压测脚本来源。真正要反复压测的项目,脚本应该以 Jmeter 原生结构为主,Badboy 只当草稿。
4. 浏览器扩展录制:前端视角快速生成脚本
4.1 扩展安装与录制前设置
浏览器扩展录制适合前后端分离项目。安装扩展后,新建录制,输入起始 URL,点击开始,然后在页面正常操作。扩展会记录 XHR/Fetch 请求,停止后可以导出 JMX 或 HAR。对 RESTful 接口来说,这种方式比代理录制更干净,因为它默认更关注接口请求,而不是页面资源。
录制前建议先清空浏览器缓存,打开开发者工具确认接口域名。如果系统有登录、验证码,建议先用测试账号登录,或者让开发提供免验证码的测试环境。录制时不要做无关操作,比如点广告、切换主题、打开帮助文档,这些都会生成垃圾请求。录完立刻停止,避免后台轮询接口混入。
4.2 导出 JMX/HAR 并导入 Jmeter
导出 JMX 最省事,直接用 Jmeter 打开,补线程组、Cookie Manager、断言即可。如果扩展只支持 HAR,就需要把 HAR 转成 JMX。常见做法是用抓包工具或转换脚本把 HAR 里的请求逐条转成 HTTP Sampler。转换后重点检查:请求方法、URL、Header、Body、认证信息是否正确。HAR 里的时间字段不要直接当压测数据,它只是抓包时间,不是性能指标。
浏览器扩展录制的请求顺序通常和用户操作一致,但压测时不一定按这个顺序。比如页面加载时并发发了 10 个接口,Jmeter 默认顺序执行,会改变压力模型。如果要做并发场景,可以用Parallel Controller插件,或者把关键接口拆到不同线程组,用同步定时器控制并发点。
4.3 处理动态参数和跨域请求
单页应用常见动态参数:CSRF Token、请求签名、时间戳、随机数。录制时这些是真实值,回放时会过期。必须用提取器从上一个响应中取。跨域请求会产生 OPTIONS 预检,如果录制里带了,压测时可以删除,因为压测直接请求接口,不涉及浏览器同源策略。但如果服务端对 OPTIONS 有特殊校验,保留也无妨。
另外,扩展录制可能把 GraphQL 请求录成一个 POST,Body 里包含 query 和 variables。这种请求参数化比较复杂,建议先用变量替换 variables 中的动态值,再压测。如果 query 本身不变,可以保留;如果不同业务查不同字段,就要参数化。
5. 抓包工具辅助录制:Fiddler/Charles 导出 HAR 再转 JMX
5.1 抓包工具代理配置与 SSL 解密
Fiddler、Charles 这类抓包工具是录制前的“显微镜”。配置代理端口,手机或浏览器指向它,安装根证书并开启 SSL 解密,就能看到 HTTPS 明文请求。录制时先过滤目标域名,避免抓到一堆无关流量。找到核心接口后,可以导出 HAR,也可以用工具自带的 Jmeter 导出功能,有些版本支持直接导出 JMX。
这种方式特别适合移动端 App、小程序、复杂 HTTPS 场景。移动端设置代理和证书的步骤与 Jmeter 代理类似,但抓包工具的证书信任流程更成熟,排查也方便。注意只抓自己有权测试的 App,不要抓第三方应用,避免隐私和合规问题。
5.2 HAR 导入 Jmeter 与请求筛选
HAR 文件本质是 JSON,包含所有请求和响应。导入 Jmeter 后,第一件事是筛选:保留业务接口,删除静态资源和埋点。第二件事是补 Cookie 和 Header。第三件事是参数化。HAR 里的响应时间不能直接作为压测结果,但可以作为接口耗时参考。
如果 HAR 里请求很多,建议按业务链路分组:登录、查询、下单、支付、退出。每组用一个Transaction Controller包起来,方便统计事务响应时间。Jmeter 的Simple Controller只做分组,不统计时间;Transaction Controller会统计整体时间,更贴近用户感知。
5.3 移动端抓包录制实战
移动端压测脚本经常需要抓 App 请求。步骤:手机连 WiFi,设置代理到电脑抓包工具,安装证书,打开 App 操作。抓到接口后,导出 HAR,再转 Jmeter。注意 App 可能有证书绑定、双向认证、请求加密,这时候抓包工具也看不到明文,需要开发提供测试包或接口文档。不要尝试绕过安全机制,测试要在授权范围内进行。
移动端脚本回放时,User-Agent、设备 ID、版本号可能需要参数化。如果服务端对设备 ID 有校验,用 CSV 准备一批测试设备 ID。如果接口有签名,必须让开发提供签名算法,或者用 Jmeter 的 BeanShell/JSR223 实现签名逻辑。
6. 录制脚本的通用后处理与压测执行
6.1 参数化:CSV、JDBC Request 与分块取值
录制完成后,参数化决定了脚本能不能模拟真实用户。最常用的是CSV Data Set Config。配置项里Filename填 CSV 路径,Variable Names填列名,Delimiter用逗号,Recycle on EOF选 False,Stop thread on EOF选 True,这样数据用完线程就停止,避免重复使用同一批数据。Sharing mode选“All threads”,所有线程共享文件;如果每个线程要有独立数据,可以选“Current thread group”或“Current thread”。
如果要在同一个 CSV 文件中让每个线程分块取值,比如 100 个线程、1000 行数据,每个线程取 10 行,可以用__threadNum和__counter组合计算行号,再用__CSVRead读取。示例思路:线程 1 取第 1-10 行,线程 2 取第 11-20 行。更简单的做法是准备多个 CSV 文件,每个线程组读不同文件。JDBC Request 参数化也很常见:先配JDBC Connection Configuration,填数据库 URL、驱动、用户名、密码,再添加JDBC Request,查询出手机号、订单号,把结果存入变量,下一个接口用${var_1}引用。注意 Jmeter 里数据库密码是明文配置,测试环境也要控制权限,不要用生产高权限账号。
6.2 关联提取:正则、JSON 提取、Token 防伪处理
关联是录制脚本能否回放的关键。JSON 接口用JSON Extractor,比如提取$.data.accessToken,变量名accessToken,默认值NotFound。HTML 页面用正则提取器,比如name="__RequestVerificationToken" type="hidden" value="(.+?)"。MVC 项目如果报__RequestVerificationToken 未提供必要的防伪标记,就是没有把页面里的隐藏 Token 提取出来并带到后续请求。解决方法:在登录页请求后加正则提取器,提取 Token,后续 POST 请求的 Body 或 Header 里带上。
RESTful 参数写法要注意:路径参数直接写在 Path,比如/api/order/${orderId};查询参数写在 Parameters;JSON Body 写在 Body Data,并加Content-Type: application/json。如果接口用了 Bearer Token,在HTTP Header Manager里加Authorization: Bearer ${accessToken}。上传文件时,HTTP Request勾选Use multipart/form-data,在 Files Upload 里填文件路径、参数名、MIME 类型。文件路径最好用相对路径或 Jmeter 变量,避免换机器后找不到文件。
6.3 断言与监控:BeanShell 断言、结果树导出
脚本跑通不等于结果可信,必须加断言。简单接口用响应断言,检查状态码、响应文本。复杂逻辑用 BeanShell 断言,示例:
String response = new String(ResponseData); if (!response.contains("\"code\":0")) { Failure = true; FailureMessage = "业务返回码异常: " + response; }BeanShell 断言灵活,但性能较差,高并发时建议用 JSR223 断言配合 Groovy。结果树可以在调试时查看请求和响应,但正式压测不要开,太耗内存。压测结束后可以导出结果树数据,或者直接用命令行生成 HTML 报告。察看结果树里可以导出 CSV、XML,方便后续分析。
6.4 压测执行:并发、Ramp-up、持续时间与云环境验证
正式压测用非 GUI 模式。线程组里设置线程数、Ramp-up 时间、循环次数或持续时间。比如模拟 100 用户并发:线程数 100,Ramp-up 10 秒,持续时间 300 秒。Ramp-up 不要设太小,否则瞬间压满,容易把服务打挂;也不要太大,否则压不到目标并发。命令行执行:
jmeter -n -t script.jmx -l result.jtl -e -o report-n非 GUI,-t脚本,-l结果文件,-e -o生成 HTML 报告。注意report目录必须不存在或为空,否则报“文件已经存在”。如果要做分布式压测,控制机执行jmeter -n -t script.jmx -R 压力机IP -l result.jtl,压力机先启动jmeter-server。压测场景可以结合迁移后的云上环境验证,比如从单节点 K8s 迁移到云上 ECS 后,用 Jmeter 脚本做高并发测试,观察 CPU、内存、数据库连接、响应时间、错误率,验证云上承载能力。这类验证不要只看 TPS,还要看 P95、P99、错误率和资源瓶颈。
7. 常见问题排查与避坑速查
7.1 录制不到请求、证书报错、乱码
| 现象 | 常见原因 | 解决方向 |
|---|---|---|
| 浏览器代理设置后无请求 | 代理端口错、Jmeter 录制器没启动 | 检查端口、启动录制器、关闭其他代理 |
| HTTPS 请求录不到 | 根证书未信任 | 导入ApacheJMeterTemporaryRootCA.crt |
| 移动端 HTTPS 抓不到 | Android 7+ 不信任用户证书 | 使用调试包或让开发配置信任 |
| 中文乱码 | 编码不一致 | jmeter.properties设 UTF-8,Sampler 设 UTF-8 |
| 录到大量静态资源 | 过滤规则没配 | Include 业务域名,Exclude 静态后缀 |
7.2 回放失败:Cookie、Token、上传、数据库密码
| 报错/现象 | 排查点 | 处理方式 |
|---|---|---|
| 登录后马上跳登录页 | Cookie/Token 没带 | 加 Cookie Manager,提取 Token 放 Header |
__RequestVerificationToken未提供 | 防伪 Token 未关联 | 正则提取隐藏域,后续请求带上 |
| 上传文件失败 | 参数名、MIME、路径不对 | 勾选 multipart,核对 Files Upload |
| JDBC 连接失败 | 驱动、URL、密码、权限 | 驱动放 lib,检查账号权限,密码用测试账号 |
| 订单号重复 | 录制值写死 | CSV 参数化,或用 JDBC 动态取号 |
7.3 高并发报错与结果分析
高并发常见java.io.IOException: error writing to server,一般是客户端端口耗尽、连接超时、服务端拒绝。排查顺序:先看压力机资源,再看 Jmeter JVM 堆,再看服务端连接数和中间件。Jmeter 默认堆可能只有 1G,压测时改jmeter.bat里的HEAP参数,比如-Xms2g -Xmx2g -XX:MaxMetaspaceSize=512m。结果分析不要只看平均响应时间,要看 90%、95%、99% 线,错误率,TPS 曲线。如果错误率随并发上升,说明服务端容量不足或脚本有共享冲突。
7.4 独家避坑清单
第一,录制脚本一定要删静态资源,不然压测数字虚高。第二,动态参数必须关联,录一次就想跑通所有并发,基本不可能。第三,参数化数据要贴近真实,手机号、订单号、用户 ID 都别用同一条。第四,正式压测前先做基准测试,1 用户、10 用户、50 用户逐步加,别一上来就 1000 并发。第五,结果文件目录不要复用,Jmeter 对已存在目录不友好。第六,压测环境要隔离,别把生产数据库压出问题。第七,脚本要版本管理,录制脚本、CSV、证书、报告分开存,方便回溯。第八,压测报告要结合服务端监控看,只看 Jmeter 结果容易被网络和压力机瓶颈误导。