刚接触性能测试的人,十有八九都会遇到同一个问题:Web端压测脚本到底怎么来?手写HTTP请求吧,业务接口一多、参数一复杂,还没写完人先崩溃了。后来我发现,最实用的入门路径其实是先学会JMeter录制,通过本地代理把你浏览器里的真实操作变成一条条可回放的压测脚本。今天这篇就围绕JMeter录制Web端压测脚本的完整操作步骤来讲,从原理到实操,再从HTTPS证书坑到脚本清洗,基本把我这几年在性能测试上踩过的坑都翻出来说一遍。
这篇文章特别适合刚入门JMeter、或者已经在用JMeter但平时主要靠手写脚本的人。录制不是万能的,但它在快速构造业务流程、复现线上操作路径、做冒烟压测这些场景下,效率确实非常高。看完你至少能独立走完一整套录制、清洗、增强、执行压测的流程,遇到问题也知道去哪找原因。
1. 先搞懂录制原理:为什么JMeter能录下你的操作
1.1 代理服务器模式:录制就是当"中间人"
JMeter录制Web端脚本,靠的是一个内置的HTTP代理服务器组件。你在浏览器里设置好代理后,所有HTTP请求都会先经过JMeter这条"管道",再转发到真实服务器。JMeter在这个过程中解析请求内容,自动生成对应的HTTP请求采样器,保存到指定的录制控制器里。
这个过程可以理解成你站在一条高速公路边上,每路过一辆车就拍一张照,记录车牌、颜色、载重,最后把所有照片整理成册。浏览器里发生的每一次点击、每一个表单提交,本质都是一次HTTP请求,JMeter把这些请求按顺序记录下来,回放时就能模拟你的完整操作流程。
这里有几个关键点需要留意:
- 代理服务器只在录制阶段启用,压测阶段不依赖它,JMeter直接向目标服务器发请求。
- 录制的请求顺序就是你的操作顺序,这对业务流程类压测很重要,比如先登录再查询再下单,顺序错乱会导致脚本直接失败。
- 录制过程中,浏览器和JMeter代理服务器必须在同一网络环境,如果JMeter跑在远程服务器上,浏览器所在机器要能访问到该服务器的代理端口。
我之前遇到不少新人问:为什么我录了半天,里面什么都没有?十有八九是代理没生效,浏览器请求压根没走JMeter这条管道。后面我会专门讲浏览器代理配置的细节。
1.2 逃避不掉的两个细节:端口和证书
JMeter的HTTP代理服务器组件默认监听8888端口,这个端口既要配置在浏览器代理里,也要保证没被其他程序占用。我建议在正式录制前先检查一下端口占用,Windows下可以用netstat -ano | findstr 8888看是不是已经有进程在监听。
另一个让很多人头疼的问题是HTTPS。Web端系统现在基本都是HTTPS协议,JMeter要录制HTTPS请求,就必须在浏览器端安装JMeter生成的根证书,否则浏览器会拦截代理流量,提示证书不受信任,录制直接失败。
关于证书的原理和导入方法,我会在第4节详细展开。这里先记住一个结论:HTTP协议可以直接录,HTTPS必须先把JMeter根证书装进浏览器的"受信任的根证书颁发机构"存储区。
1.3 录制和手写脚本怎么选
录制不是万能的,它最大的优势是快,尤其是当你面对一个完全陌生的系统时,手工分析接口参数可能要半天,录制五分钟就能跑起来一条完整业务流程。
但录制脚本也有明显的短板:脚本里会混入大量静态资源请求、冗余Cookie、无关的AJAX轮询请求,直接拿去压测,请求数量虚高,结果失真。另外,录制下来的脚本参数都是硬编码的,多用户并发时无法模拟不同账号、不同数据的场景。
我的经验是:业务接口数量多、前端加密参数复杂、需要快速复现真实操作路径时,优先用录制来打底;接口很简单、只有两三个核心交易接口时,手写脚本反而更干净。但不管用哪种方式,录制出来的脚本必须要经过清洗和增强,就像原材料一定要加工后才能上桌一样。
2. 环境准备:装对JDK和JMeter,比什么都重要
2.1 版本怎么选:JDK与JMeter版本关系
JMeter是Java应用,需要JDK环境。我个人推荐直接装JDK11或JDK17,JMeter 5.x系列对这两个版本支持都很好,尽量避免用太老的JDK7或JDK8,因为新版JMeter的一些组件和插件在老JDK上会报不兼容问题。
下载JMeter时认准Apache官方下载页面,选择binaries压缩包,Windows下就是zip,Linux下是tgz。解压后先配置JAVA_HOME环境变量,指向JDK安装目录,然后在命令行执行:
java -version jmeter -v两个命令都能正常输出版本信息,说明环境没问题。如果java -version能识别但jmeter -v不行,一般就是PATH里没有包含JMeter的bin目录,去环境变量里补上即可。
JMeter的目录结构也值得看一眼。bin目录是启动入口和核心配置文件所在,lib/ext是插件和扩展jar包的位置,lib目录存放运行依赖。以后你装第三方插件,基本就是往lib/ext里放jar包,或者通过插件管理器自动安装。
2.2 首次启动和界面语言
Windows下进入bin目录双击jmeter.bat启动,我建议第一次启动时用中文界面,选择菜单栏的Options -> Choose Language -> Chinese,JMeter会记住这个设置。某些老版本需要手动改配置文件:打开bin/jmeter.properties,找到language这个参数,去掉注释并改成zh_CN。
启动后默认带一个测试计划,保存为.jmx文件,这是JMeter脚本的标准格式,压测时命令行执行的就是这个文件。我建议从一开始就给脚本文件建好规范的命名,比如order_pressure_2025_v1.jmx,否则后面脚本版本多了根本分不清哪个是哪个。
另外强调一句:JMeter的GUI模式是用来写脚本和调试脚本的,不是用来压测的。真正的压测执行建议全部用命令行模式,这一点在第6节会详细说明。
2.3 需要的插件:哪些对录制和压测有用
录制本身不需要任何额外插件,JMeter自带的HTTP代理服务器组件就够用。但我建议安装JMeter Plugins Manager插件管理器,后面做性能监控、图形化指标扩展时会用到。
安装方式很简单:从官方插件管理器的Github仓库下载plugins-manager.jar,放到lib/ext目录,重启JMeter后,菜单栏会出现Plugins Manager选项,在里面搜索你需要的插件一键安装。注意安装完插件同样需要重启JMeter才能生效。
需要提醒的是,插件不是越多越好。压测时很多插件会额外消耗资源,尤其是一些图形化插件,在集群压测和高并发下反而拖累性能。录制阶段装个插件管理器就够了,其他组件等真正需要时再装。
3. 录制Web端压测脚本的完整操作步骤
3.1 第一步:搭好录制骨架
打开JMeter后,先按照下面这个顺序把录制骨架搭起来:
- 在测试计划下添加一个线程组,线程数先填1,用来录制和调试,跑压测时再改成实际并发数。
- 在线程组下添加逻辑控制器里的"录制控制器"。这个控制器专门用来存放录制生成的采样器,建议把它重命名为"录制脚本",方便识别。
- 在测试计划下添加非测试元件里的"HTTP代理服务器"。
HTTP代理服务器的配置有几个关键项要设置:
- 端口:默认8888,保持不变即可。
- 目标控制器:下拉框选择
测试计划>线程组>录制控制器,这样录出来的脚本会自动挂到指定的录制控制器下,而不是散落各处。 - 分组:我习惯选择"每个分组放入一个新的控制器",这样JMeter会尝试按页面或事务对请求分组,录制后脚本结构更清晰。
- 录制模式:选择HTTP客户端4或HTTP客户端3都行,一般按默认即可。
- 勾选"捕捉HTTP头信息",这样能录到请求头里的重要内容,比如Content-Type、Cookie。
- "添加断言"建议不要勾选,断言我们后面根据需要手工加,录制时自动加的断言往往不是我们想要的。
配置完基本就是这个样子。这里还有个小技巧,录制前把目标服务器地址在HTTPS Domains里填上,比如被测系统是www.example.com,填到HTTPS Domains那一栏,可以避免把其它域名的请求也录进脚本。
3.2 第二步:配置浏览器代理
这步是很多人卡住的地方。JMeter代理服务器启动后,浏览器必须把流量指向它,否则你就算在页面上点半天,录制控制器里依然空空如也。
以Chrome为例,最简单的方式是使用系统代理:
- 打开Chrome设置,搜索"代理",点击打开代理设置。
- 在Windows的Internet属性里,打开"局域网设置"。
- 勾选"为LAN使用代理服务器",地址填
127.0.0.1,端口填8888。 - 这里特别提醒:需要取消"本地地址不使用代理"这个选项,因为我们要录制的目标地址可能是内网IP,一旦勾选了,浏览器访问内网系统时就会绕过代理,导致录不到数据。
如果觉得每次改系统代理太麻烦,可以安装Chrome的SwitchyOmega扩展,在里面新建一个代理情景模式,协议选HTTP,服务器填127.0.0.1,端口填8888,需要录制时一键切换,不用录制时切回直连模式,比手动改系统代理高效很多。
Firefox和Edge的配置逻辑完全一样,都是设置代理服务器地址和端口。录制过程中我建议打开浏览器的无痕模式,并且把浏览器上所有插件都停用,特别是广告拦截类插件,它们会产生额外的代理流量请求,把脚本污染得乱七八糟。
3.3 第三步:设置过滤规则,别把静态资源录进来
这一步非常关键。一个现代Web页面打开时会加载几十个静态资源文件,JS、CSS、图片、字体、图标,哪个都不是你压测关心的业务接口。如果不做过滤,这些请求会全部录进脚本,压测时不仅造成请求量虚高,还会干扰服务器性能数据的真实性。
在HTTP代理服务器的"排除"配置里,我通常加上这样一条正则表达式:
.*\.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|map)(\?.*)?$这条正则的含义是:任何以这些静态资源后缀结尾的URL,不管后面带不带查询参数,都直接排除掉,不录进脚本。实际使用中,根据被测系统的资源类型可以灵活增删后缀。
除了静态资源,还有很多前端埋点、监控上报的请求也应该排除,这些请求往往带有collect、analytics、track、log之类的关键字。可以在排除规则里再加一条正则:
.*(collect|analytics|track|report|monitor).*过滤规则是录制脚本质量的第一道防线,宁可规则稍微严格一点,也别让垃圾请求混进来。当然也别过滤得太狠,核心业务接口肯定不能过滤掉,这个度需要你对自己的被测系统有基本了解。
3.4 第四步:启动代理、操作业务、停止录制
配置全部就绪后,点击HTTP代理服务器上的"启动"按钮。如果是第一次录制HTTPS网站,JMeter会弹出一个根证书向导,提示需要安装证书到浏览器,这里按提示操作,证书问题第4节会单独讲。
启动成功后,打开浏览器并切换到代理模式,在地址栏输入被测系统网址,然后按你的测试场景设计,一步一步操作页面。比如要压测"用户登录后查询订单"这个流程,就先登录、再进入订单页面、查询、退出,每个步骤都停顿一两秒,尽量模拟真实用户的操作节奏。
操作完成后,回JMeter点击HTTP代理服务器的"停止"按钮。这时你会看到录制控制器下面出现了一串HTTP请求采样器,排列顺序基本对应你的操作时序。先别急着高兴,到这里只完成了30%的工作,接下来的脚本清洗和增强才是大头。
4. HTTPS录制与证书:最容易翻车的一环
4.1 为什么会遇到证书报错:中间人解密原理
HTTP协议是明文传输,代理直接转发就行。但HTTPS在传输前会做TLS加密,浏览器和服务器之间要完成握手和证书校验。代理服务器想看到请求内容,就必须让浏览器信任它这个"中间人",所以JMeter会生成一个根证书,你需要把这个证书安装到浏览器的受信任区。
装上证书后,JMeter就能解密HTTPS流量,把请求内容解析成采样器。如果证书没装对,浏览器会报ERR_CERT_AUTHORITY_INVALID之类的错误,严格的时候连页面都打开不了,或者点几次就被拦下来。
很多新手在这里反复踩坑,第一个坑是把证书装到了"个人"证书区,而不是"受信任的根证书颁发机构";第二个坑是证书装好后没有彻底关闭浏览器再重启,浏览器进程还在内存中缓存旧状态,导致证书校验还是失败。
4.2 证书导入实操步骤
JMeter的根证书文件在bin目录下,文件名是ApacheJMeterTemporaryRootCA.crt,注意这个文件名里带Temporary,因为它是有有效期的临时根证书。
导入步骤以Windows + Chrome为例:
- 双击
ApacheJMeterTemporaryRootCA.crt,弹出证书信息窗口。 - 点击"安装证书",存储位置选"本地计算机"。
- 选择"将所有证书都放入下列存储",点击"浏览"。
- 选择"受信任的根证书颁发机构",确认并完成导入。
- 完全关闭浏览器,重新打开,再访问HTTPS站点。
导入成功后,不需要对证书有任何恐慌或误解,这只是测试工具用于解密流量生成脚本的正常机制。如果录制完成,想彻底移除证书,可以在Windows运行里输入certmgr.msc打开证书管理器,找到"受信任的根证书颁发机构",搜到JMeter对应的证书,右键删除即可。
4.3 录制HTTPS时常见报错与处理
我整理了一下录制HTTPS时最常遇到的几个现象,按照排查优先级大致是这样:
- 浏览器打开页面提示
证书不受信任或您的连接不是私密连接:说明JMeter根证书没有被浏览器正确信任,重新导入一遍,确认放在"受信任的根证书颁发机构"。 - 录制一开始有数据,中途突然断掉:大概率是证书有效期问题或者浏览器缓存异常,重新启动代理服务器试一次。
- 代理启动后,所有HTTPS站点都打不开:先停掉代理,恢复浏览器直连,然后把浏览器缓存清一下再重试。如果确定是证书问题,重新生成证书再导入。
- 公司统一安装安全软件拦截了本地代理:这种情况只能和网管或安全团队协商,或者改用内网专用的压测环境去录制。
这里补充一个很实用的小经验:如果换了一个新的被测系统,尤其是跨越时间比较久之后,旧的JMeter证书可能已经失效,重新启动代理服务器时会自动生成新的证书,这时需要在浏览器里把旧证书删掉,重新导入新证书,不然会一直报错。
5. 录制完不等于能用:脚本清洗与增强
5.1 第一步清洗:删掉静态资源和无效请求
打开录制控制器,逐个检查采样器。即使过滤规则已经挡掉了大部分静态资源,依然会有漏网之鱼,比如接口返回的JSON里有Base64图片、动态生成的验证码图片、某些根据URL参数动态加载的资源。
清洗的标准很简单:只看业务相关的核心请求。比如登录接口、查询接口、下单接口、支付接口,这些才是压测关注的对象。其它回答不了"这个请求属于哪一步业务"的,都可以禁用或删除。
删除请求时要注意:有些请求虽然单独看不重要,但它在业务流程中承担了关键作用。比如登录后获取用户信息、获取Token的请求,把它们删掉会导致后续请求直接失败。我的做法是:先在查看结果树里运行一遍录制好的脚本,根据报错情况判断哪些请求是业务链路中的必需环节,而不是盲目删除。
5.2 第二步增强:加断言和参数化
干净的脚本要能验证请求是否成功。最直观的方式是加响应断言,比如判断登录接口的响应中是否包含success或欢迎xxx这类关键字。但有些系统的返回结构很复杂,响应断言的关键字可能没法精确匹配,这时可以上BeanShell断言。
在采样器下添加"BeanShell断言",写入类似下面的代码:
String resp = prev.getResponseDataAsString(); if (resp.contains("success")) { Failure = false; } else { Failure = true; FailureMessage = "响应中未找到success关键字,请求可能失败"; }这段脚本的逻辑是:取上一个采样器的响应内容,如果包含success就判定通过,否则标记失败并给出失败原因。当然实际业务里判断的关键字要根据系统返回内容来定,比如错误码是code: 0还是status: 200,见过响应格式之后改一下关键字就行。
参数化则是为多用户压测准备。最简单的做法是使用CSV Data Set Config组件,准备一个包含用户名密码的CSV文件,配置好变量名,然后在请求参数里引用${username}、${password},这样每个虚拟用户都能取到不同的账号。
5.3 第三步:思考时间、循环和多用户模拟
录制脚本里每个请求之间几乎是没有间隔的,这不符合真实用户行为,全速请求会让服务器压力失真。压测时通常有两个方向:如果是模拟极限压力,思考时间可以直接去掉,或者设置极短的值;如果是模拟真实业务场景,需要加常数吞吐量定时器或高斯随机定时器,让请求间隔更接近真实分布。
线程组参数这里再说一下:压测时把线程数改成你计划的并发数,比如100个用户,循环次数填-1并勾选调度器,设置持续时间,比如压5分钟。使用Ramp-Up Period控制用户启动的速度,我一般建议线程总数除以每秒启动数,控制在30到60秒内把所有用户都启动起来,这样能避免瞬间冲击造成的假错误。
多用户模拟还有个关键点就是必须做参数化,否则所有用户都用同一个账号,要么被系统踢下线,要么被测系统账号体系直接报错。
5.4 关联:处理动态Token的入门写法
很多Web系统在登录后会返回Token、SessionId等动态参数,这些参数在后续请求中要作为请求头或请求体的一部分携带。录制脚本里这些值已经写死了,一旦换个用户、换次登录,就会失效。
解决方式是加关联(动态提取)。最常用的是正则表达式提取器,放在登录请求下面,提取响应中的Token值,然后在后续请求中用${token}引用。举一个简单例子,如果登录响应里是一段JSON:
{ "data": { "token": "abcdef123456" } }在正则表达式提取器里配置:
- 引用名称:token
- 正则表达式:
"token"\s*:\s*"([^"]+)" - 模板:
$1$ - 匹配数字:1
提取完之后,给后续请求加上HTTP头管理器,传入token: ${token}。这样脚本就具备跨会话的能力了,用户A登录取的Token不会带到用户B的请求里,因为每个线程组的每个线程都有自己独立的变量副本。
6. 从录制脚本到压测报告:跑起来看数据
6.1 用GUI跑还是命令行跑:命令行更稳
脚本清洗增强完毕后,就可以正式压测了。这里有个很多人容易忽略的重要事项:不要在GUI界面上直接跑高并发压测。
GUI模式本身会消耗大量内存和CPU来绘制图表、更新界面,JMeter进程的负载会干扰压测结果。正确做法是保存脚本后,用命令行执行:
jmeter -n -t web_pressure_test.jmx -l result.jtl -e -o /path/to/report参数含义如下:
-n:非GUI模式运行。-t:指定测试计划文件。-l:保存采样结果的JTL文件路径。-e:压测结束后生成HTML报告。-o:HTML报告的输出目录,注意这个目录必须不存在或为空,否则会报错。
跑完之后,进入输出目录打开index.html,就能看到完整的测试报告。带-e参数最大的好处是不需要人工整理监听器,报告页面已经把所有核心指标可视化好了。
6.2 常用监听器与报告指标解读
录制和调试阶段我用得最多的是"查看结果树"和"聚合报告"。查看结果树用来逐条确认请求响应是否正确,聚合报告用来快速确认错误率和响应时间。
聚合报告里重点看这几个字段:
- 样本数:总请求数,可以用来判断吞吐量是否稳定。
- 平均响应时间:所有请求的平均耗时。
- 90%百分位:90%的请求都在这个时间内完成,这个指标比平均值更皮实,不容易被极端值带偏。
- 错误率:错误请求占总请求数的比例,压测时错误率应该趋近于0。
HTML报告里还可以看APDEX(应用性能指数)、TPS曲线和响应时间分布。判断系统能否支撑预期压力,一般看两个硬指标:TPS是否达到目标值,错误率是否在可接受范围。响应时间是否超时,要结合业务需求来定,不是说越短越好。
6.3 压测过程中的实时观察
命令行压测过程中看不到实时效果,这时候有两个办法。第一个是在脚本里添加"后端监听器"配合InfluxDB和Grafana,搭建实时监控看板,适合正式压测;第二种是临时在负载机上直接看JTL文件的变化:
tail -f result.jtl每新增一行就代表一个采样结果,可以看到响应时间、状态码等信息。虽然不是结构化展示,但快速判断接口是否大面积失败还是够用的。
如果你发现压测刚开始错误率就很高,不要先看监控平台,先去JTL文件里看具体的HTTP状态码和错误摘要。状态码503说明服务器过载,500说明业务异常,连接超时则需要检查网络和负载机压力。定位问题方向远比盯着某一个指标发呆有效。
7. 常见问题与排查陷阱:我踩过的坑
7.1 高频问题速查表
我把实际工作中遇到的高频问题整理成了表格,方便你直接对照排查。
| 现象 | 可能原因 | 排查和处理方法 |
|---|---|---|
| 代理启动后浏览器打不开网页 | 代理配置错误,或端口8888被占用 | 检查代理地址和端口;用netstat检查端口占用,换个端口重配 |
| 录制控制器里没有任何请求 | 浏览器流量没走代理;过滤规则把所有请求都过滤掉了 | 打开代理模式再试;暂时清空排除规则,确认能录到再逐条加回 |
| HTTPS站点提示证书无效 | JMeter根证书未正确导入 | 重新导入到"受信任的根证书颁发机构",重启浏览器 |
| 录制成功后脚本里响应中文乱码 | 采样器编码不对 | 先检查查看结果树里的响应编码,将HTTP请求的Content Encoding设为UTF-8;修改bin/jmeter.properties里的sampleresult.default.encoding=UTF-8 |
| 命令行压测时报目录已存在 | -o参数指定的目录已存在 | 换一个空目录,或者在执行前删掉旧目录 |
| 压测初期大量失败,接口提示未登录 | 脚本中的Token、Cookie等动态参数未做关联 | 补充正则表达式提取器,提取登录后返回的动态凭证 |
这些问题的共同根源,大多数都是配置细节没到位。录制脚本出问题,优先检查代理配置和过滤规则;压测时出问题,优先检查参数化和关联。
7.2 压测时报连不上目标服务
压测过程中如果看到org.apache.http.conn.HttpHostConnectException: Connect to ...这类错误,说明JMeter在向目标服务器发送请求时连接建立失败。排查顺序是这样:
先用ping确认网络能不能通,再用telnet 目标IP 端口确认目标端口是否开放,最后确认压测脚本里的服务器名称或IP是否填写正确。如果服务器本身没问题,大概率是防火墙规则挡掉了负载机的IP,或者是压测环境本身的网络策略限制并发连接数。
还有个容易忽略的地方:脚本里HTTP请求的协议配置,是HTTP还是HTTPS,要和目标服务实际协议一致,HTTPS的443端口配成HTTP,请求发出去立刻就是一堆错误。
7.3 一点关于录制压测脚本的个人建议
最后分享几条我实际做项目时的体会。
录制脚本最大的价值,是帮你快速搭出符合真实业务流程的压力模型。但它的上限,取决于脚本清洗和增强这两步做得够不够细致。很多团队拿录制脚本直接上压测,结果出来的数据要么虚高,要么错误率诡异,最后怀疑这怀疑那,唯独没怀疑脚本本身。
我的建议是:清洗阶段宁慢勿快,每条请求都确认它是干什么的;增强阶段宁多勿少,断言、参数化、关联一个都不能省。脚本第一次保存后,先用1个线程、1次循环跑通全链路,确认无报错、断言通过后,再逐步增加并发。这个顺序能帮你过滤掉至少80%的脚本问题。
再补充一个小技巧:录制的脚本最好保存多个版本,原始录制版、清洗版、参数化版,每个阶段单独存一份。这样压测结果出现异常时,可以对比不同版本的脚本,快速定位是哪个环节引入了问题,排查效率会高很多。