JMeter | BeanShell入门级编写

作者:Mars酱

声明:文章由作者原创,欢迎转载,转载前请联系我!

需求说明

公司准备做压力测试,业务场景是模拟1000个用户访问服务器接口,以检测自己的卡片是否真实有效。由于服务器端是做了鉴权校验的,只允许发放了密钥对的用户在做好签名编码后,才可以检查卡片是否真实有效。因此我们在发送请求前要通过密钥对做好签名,最后发送给服务端做鉴权校验和卡片检查。

后端签名的方式是把所有参数按顺序拼接好,最后再拼接上密钥的加密key,把整个参数字符串做md5编码,便可以得到签名串sign,后端检测收到的参数和服务端自行加密签名得到的签名串一致,则允许通过鉴权,并做后续的卡片检查业务。

后端签名校验逻辑(请忽略代码规范和性能,目的只为解释后端逻辑),如下:

// 获取客户端发送的请求参数
// accessKeyId
String accessKeyId = request.getParams("accessKeyId");
// 卡号
String cardNo = request.getParams("cardNo");
// 随机数
String nonceStr = request.getParams("nonceStr");
// 时间戳
String timestamp = request.getParams("timestamp");

// 通过客户端accessKeyId找到发放给客户端的加密密钥
String key = getKey(accessKeyId);

// 所有参数按照顺序拼接好
String params = "accessKeyId=+ accessKeyId;
params +=&cardNo=" + cardNo;
params +=&nonceStr=" + nonceStr;
params +=&timestamp=" + timestamp;

// 最后拼接上key
params += "&key=" + key;

// 再做md5编码, 得到签名
String serverSign = md5(params);
System.out.println(“sign=+ sign);
// 输出如下:
// sign=736E3E80E70CDB3246C28664739452EC

// 拿到客户端传递的sign签名串
String clientSign = request.getParams("sign");
// 把服务端的签名sign和客户端的对比,如果相等,则处理后续业务,否则为非法访问!
if(serverSign.equals(clientSign)){
    // ... 校验卡片信息是否真实有效
}
    

客户端发送的请求参数需要与服务端参数拼接顺序一致,如下:

https://www.domain.com/api/card_external/cardinfo/check?accessKeyId=6aYkjYFJ&cardNo=1000000002070270&nonceStr=nNEaWSmTMDZrZkin×tamp=1678365035148&sign=736E3E80E70CDB3246C28664739452EC

工具选择

压测主要模拟客户端请求服务端,作为一个java开发首选肯定是java派系测试工具

JMeter | BeanShell入门级编写_第1张图片

JMeter版本:Apache JMeter 5.5

JDK:OpenJDK 16

准备工作

由于模拟客户端发送请求,因此测试前需要根据业务场景的需求提前准备以下数据:

  1. 密钥对(accessKeyId、key) 。密钥对由服务端发放,其中包含accessKeyId和key,其中accessKey相当于账号,key相当于密码用来加密使用;
  2. 客户端需要校验的卡号(cardNo) 。卡号我们不能使用同一张卡,因为模拟不同的用户,所以要准备一大批卡号;
  3. 随机数(nonceStr) 。防止伪造,因此在生成签名串的时候加入随机数,随机数可以是任意方式,比如:随机数字 + 随机字母、纯随机数字、纯随机字母等等;
  4. 时间戳(timestamp) 。作用同样是防止伪造,增加防伪造的难度;
  5. 签名(sign) 。发送给服务端用来比对是否合法请求;

操作步骤

以上5种数据,我们需要在JMeter中对应的准备好。根据java编码方式,所有参数应该都是变量,最后在发送get请求的时候引用变量并发送给接口

1. 准备好HTTP请求配置

既然发送http的请求,因此我们先添加http请求的配置节点,选择菜单如下:

JMeter | BeanShell入门级编写_第2张图片

在“HTTP请求”节点的配置界面填写上请求地址信息,主要配置页面需要填写以下红框中的内容,如下:

JMeter | BeanShell入门级编写_第3张图片

协议: 在协议部分写清楚服务端使用的是什么方式,我需要请求的目标服务器是https协议,因此我填写了https。

服务器名称或者ip: 写上自己服务器的ip地址+port端口号,有域名的写上完整域名。我是有域名的,因此只要写域名即可。

HTTP请求方式: 我的业务场景主要是GET请求,因此选择GET

路径: 这里需要注意,一个完整的接口应该由域名 + 上下文路径 + 请求参数组成,如下:

https://www.domain.com/api/card_external/cardinfo/check

https://www.domain.com 是域名

api/card_external/cardinfo/check 是上下文路径

而且get请求一般都是直接在接口后面直接跟参数,如:

http://www.domain.com/api/card_external/cardinfo/check?key1=value1&key2=value2&key3=value3

由于是get请求,因此,路径部分应该在get请求中是上下路径 + 请求参数,如:

api/card_external/cardinfo/check?key1=value1&key2=value2&key3=value3

在平时的开发工作中key和value都应该是变量填充,因此我们通过JMeter测试工具也应该是模拟去填充值,所以,红框中的内容我们填写如下:

api/card_external/cardinfo/check?accessKeyId=${accessKeyId}&cardNo=${carno}&nonceStr=${nonceStr}×tamp=${timestamp}&sign=${sign}

以上路径中主要引入了以下变量 ${accessKeyId} ${cardno} ${nonceStr} ${timestamp} ${sign},因为我们模拟不同的用户,所以这几个参数的值是会变化的。

而变量名使用${...}符号方式包裹,是因为JMeter的使用规则。

2. 创建用户自定义变量

配置好HTTP请求和引入变量之后,我们就需要声明这些变量,变量的声明在JMeter中是通过“用户定义的变量”节点去声明的,添加好节点:

JMeter | BeanShell入门级编写_第4张图片

在配置界面声明好变量,此处的变量名需要与“HTTP请求”配置中引入的变量名一致,如下:

JMeter | BeanShell入门级编写_第5张图片

在此,我们只声明了四个变量accessKeyId nonceStr timestamp sign ,其中,除了accessKeyId变量的值固定写死,其余的变量值都是随便写,因为这几个变量在后面会需要重新赋值的。

细心的朋友也会发现${cardno}变量没有在此声明。那是由于我们需要模拟1000个用户,每个用户1张卡,因此我们需要有卡池,卡池和${cardno}变量的声明往下翻。

3. 准备好卡池数据

JMeter支持csv格式文件的读取,因此我们把卡池数据存放在csv文件中。

4. 引入卡片数据和变量

卡池准备好了,那么我们就需要完成${cardno}变量的声明了,选择“配置元件”中的“CSV Data Set Config”:

JMeter | BeanShell入门级编写_第6张图片

然后在“CSV 数据文件设置”菜单中配置,如下:

JMeter | BeanShell入门级编写_第7张图片

文件名: 选择卡池csv文件的本地存放路径;

变量名称(细纹逗号间隔): 填写变量名cardno,此处与HTTP请求配置中cardNo=${cardno}的变量必须对应。

其余的配置使用默认选项。

5. BeanShell取样器

HTTP请求的变量引入了,引入的变量也声明了,卡池也准备好,卡片变量名也声明了,那么现在就在在发送请求之前做好最后一步工作:给所有变量名赋值!

我们需要赋值的变量名已经在“HTTP请求”配置引入,主要是: ${accessKeyId} ${cardno} ${nonceStr} ${timestamp} ${sign}

在JMeter中赋值操作主要使用“BeanShell取样器”来完成,取样器中是需要编写java代码的,因此我们先来添加“BeanShell取样器”节点:

JMeter | BeanShell入门级编写_第8张图片

在打开的配置界面中编写好java代码,完成赋值过程,截图如下:

JMeter | BeanShell入门级编写_第9张图片

核心来了!BeanShell中的java代码如下:

/** author: mars酱 */
import org.apache.commons.codec.digest.DigestUtils;
import java.util.Date;
// 1. 取变量名,不是取url的key值
String accessKeyId = vars.get("accessKeyId");
// 2. 取卡号
String cardNo = vars.get("cardno");

// 3. 随机数
String nonceStr = vars.get("nonceStr");
nonceStr = "";
String chars = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz";
int maxLen = chars.length();
for (int i = 0; i < 16; i++) {
	double floor = Math.floor(Math.random() * maxLen);
	int intValue = (new Double(floor)).intValue();
	nonceStr += String.valueOf(chars.charAt(intValue));
}
vars.put("nonceStr", nonceStr);

// 4. 时间戳
String timestamp = new String();
Date date = new Date();
timestamp = String.valueOf(date.getTime());
vars.put("timestamp", timestamp);

// 5. 密钥
String key = "e992fdbec7cd1eb2b1c6c8e07d4eea60";

// 6. 拼接待签名的参数值
String params = "accessKeyId=" + accessKeyId + "&cardNo=" + cardNo + "&nonceStr=" + nonceStr + "×tamp=" + timestamp + "&key=" + key;
log.info("拼接后的参数:{}", params);

String sign = "";
// 7. md5签名整个参数
sign = DigestUtils.md5Hex(params).toUpperCase();
vars.put("sign", sign);

BeanShell取样器的java代码中有vars变量,这个是JMeter的内置变量,会在最后一节简单解释。

ok,http请求的所有配置赋值工作到此已经完成,但是在发送请求之前,我们还需要监听发送之后的响应结果,因此我们还需要添加监听器

6. 添加监听器

监听器的作用是监听响应结果,主要添加三种监听器节点,也可以根据自己的情况适当选择,我主要添加了:

查看结果树

JMeter | BeanShell入门级编写_第10张图片

汇总报告

JMeter | BeanShell入门级编写_第11张图片

聚合报告

JMeter | BeanShell入门级编写_第12张图片

执行测试

到此,所有的请求配置、请求中变量赋值、卡池数据、监听结果报告都已经配置完成。最后,在线程组中设置好需要测试用的线程数、Ramp-Up时间等参数后,点击顶部“”按钮,开始运行

JMeter | BeanShell入门级编写_第13张图片

查看结果

三个不同的监听器通过不同的维度展示整个压测的结果

查看结果树

JMeter | BeanShell入门级编写_第14张图片

“BeanShell取样器”相当于ide的调试,可以查看到编写的java脚本是否有错误,飘绿说明正确,可以通过切换“取样器结果”、“请求”、“响应数据”三个不同的选项卡查看自己需要的结果;

“调试取样器”是对“BeanShell取样器”的监听,主要是看是否在“BeanShell取样器”的编译结果是否正确,需要添加“调试取样器”节点

JMeter | BeanShell入门级编写_第15张图片

选择“查看结果树”中的“调试取样器”可以查看结果,主要查看“响应数据”,其结果是“BeanShell取样器”生成的调试结果:

JMeter | BeanShell入门级编写_第16张图片

“查看结果树”中主要看“HTTP请求”选项的结果:

JMeter | BeanShell入门级编写_第17张图片

选择“请求”选项卡,可以看到发送服务端的完整请求地址和填充好的变量值:

JMeter | BeanShell入门级编写_第18张图片

还有服务端的响应结果:

JMeter | BeanShell入门级编写_第19张图片

汇总报告

JMeter | BeanShell入门级编写_第20张图片

聚合报告

JMeter | BeanShell入门级编写_第21张图片

到此,使用JMeter模拟发送get请求已经完成,主要使用JMeter内置变量完成参数填充。
下面简单提两句内置变量:

JMeter内置变量说明

vars和props都是jmeter的内置变量,不必先定义,可以直接使用。

1.vars 只能在当前线程组使用(局部),props 可以跨线程组使用(全局)

2.vars 只能保存 String 或 Object ,props 是 Hashtable 对象

搬运自己掘金:JMeter | BeanShell入门级编写

你可能感兴趣的:(jmeter,java)