转载:JMeter处理动态的签名内容 - z417 - 博客园 (cnblogs.com)
先贴脚本,大神请直取
新建线程组 → http取样器 → 前置处理器 → bean shell 预处理程序
importorg.apache.commons.codec.digest.DigestUtils;importjava.util.Date;importorg.apache.jmeter.config.*;importcom.alibaba.fastjson.JSON;// 文末有fastjson.jar的链接importcom.alibaba.fastjson.JSONObject; Arguments args = sampler.getArguments();// 截获请求,包含url、headers 和 body 三部分Argument arg_body = args.getArgument(0);// 获取请求bodyString body = arg_body.getValue();// 获取body的值保存成字符串log.info(body);// 打印下看看,跑压测时勿忘把log注掉JSONObject jso = JSON.parseObject(body);// 把body转成json对象,注意!这里因为body本身就是json字符串,所以用json类处理,xml或其他格式的不能这样处理!!String AppKey = jso.getString("AppKey");// 获取body中的AppKey,下面签名会用到String Data = jso.getString("Data");// 获取Data,下面签名会用到log.info("登录的Data : "+ Data); Date date =newDate();//将时间戳截取到秒的量级(长度共10位)String timestamp = String.valueOf(date.getTime()/1000);String key ="a323f9b6-1f04-420e-adb9-b06ty67b0e63";String bsign = AppKey + timestamp + Data + key;String sign = DigestUtils.md5Hex(bsign);//替换 timestamp 和 sign 字段的值到jsonObjectjso.put("TimeStamp",Integer.parseInt(timestamp));jso.put("Sign",sign); body = jso.toString();arg_body.setValue(body);// 将新body替换到取样器的参数中,实现了截获 → 修改 → 发送修改后的内容
小白请从这里看起
上回在"接口签名(sign)"末尾遗留了个问题,现在来填坑;
待签名的内容中,手机号的值会动态变化,签名就会校验失败。所以需要jmeter能动态处理待签名的内容;
前文提到有两种方式处理该问题,这里重点介绍较折腾的一种;文末会简单介绍第2种。
原始请求示例
向api发送手机号,查询归属地,json消息
{"AppKey":"z417App","AppVer":"5.0.4","Data":"{
\"Mobile\":\"${Mobile}\",
\"PlatType\":101,
\"RegSource\":2,
}","Lang":"CN","Sign":"12c52b95f3af5bacddcee2b792d1a652","TimeStamp":1560220395}
分析请求
① 传了签名,签名内容是AppKey + Data + TimeStamp + secretKey(值跟开发要)
② Data 的值是个字符串,只不过是 String like Json
③ 要根据变换的Mobile动态替换Sign
解决思路
a. 获取AppKey的值
b. 提取请求中的Data的值:${Mobile}参数化,处理时不用关注具体值;
c. 要提取并编辑json格式的内容, 需要用到处理json对象的工具包 fastjson
d. TimeStamp虽然在签名内容之列,但这里不用提取,运行时给它传一个实时的就行
e. 按签名算法完成签名计算
f. 将签名和签名时用的TimeStamp,替换到request body中
再来细看bean shell脚本
importorg.apache.commons.codec.digest.DigestUtils;//里面有md5Hex()方法,返回(32位[大])签名后的内容importjava.util.Date;//里面有生成当前时间戳的方法importorg.apache.jmeter.config.*;//里面有截获request body的方法// 以上jar包自带,可放心导入;下面两个来自阿里的fastjson包,文末有下载链接importcom.alibaba.fastjson.JSON;//序列化与反序列化importcom.alibaba.fastjson.JSONObject;//创建json对象
下载fastjson放到jmeter的plugins专用目录,如我的:
E:\DownLoad\Software\apache-jmeter-3.1\lib\ext
来看看如何截获sampler的请求
Arguments args = sampler.getArguments();// 包含url、headers 和 body 三部分Argument arg_body = args.getArgument(0);// 获取request bodyString body = arg_body.getValue();// 将request body保存成字符串log.info(body);// 打印下看看,跑压测时勿忘把log注掉
Arguments:api文档解释如下 :
A set of Argument objects. Argument对象的set集合 ,那Argument是什么呢?不慌~
sampler:api文档描述如下:
Common constants and methods for HTTP samplers. HTTP取样器的常用常量和方法。
Arguments 对象有一个方法 getArgument(),api文档描述如下:
//大体意思是接受一个索引,返回该索引对应的值,这个值是 Argument 类型的数据。
public Argument getArgument(int row)
Get a single argument.
Parameters:
row - the index of the argument to return.
Returns:
the argument at the specified index, or null if no argument exists at that index.
Argument 类型:api文档描述如下
//大体意思是由键值对(key,value)组成的一个对象。
A set of Argument objects.Class representing an argument. Each argument consists of a name/value pair, as well as (optional) metadata.
Argument 对象有getValue(),api文档描述如下:
//大体意思是以字符串类型,返回Argument 对象中属性的值。
public java.lang.String getValue()
Gets the value of the Argument object.
Returns:
the attribute's value
至此,我们已经把request body拿到了,可以用日志打印下看看:
log.info(body);//不出意外获得的会是一个字符串
再次看看request body
{"AppKey":"z417App","AppVer":"5.0.4","Data":"{
\"Mobile\":\"${Mobile}\",
\"PlatType\":101,
\"RegSource\":2,
}","Lang":"CN","Sign":"12c52b95f3af5bacddcee2b792d1a652","TimeStamp":1560220395}
确定会动态变化字段,这里有3个:Mobile,Sign,TimeStamp;
Mobile 的值已经用参数化管理起来了;
Sign 的值会因为每次传参的变化而变化,比如每次更新后的 Mobile 的值;
TimeStamp 时间戳,每次请求都不一样。
大招一开
body是个String类型的json,需要转成json类型:
JSONObject jso = JSON.parseObject(body);//转成json对象
准备签名(Sign)需要的内容并签名,不讲签名知识了,前文有提及:
String AppKey = jso.getString("AppKey");//获取AppKeyString Data = jso.getString("Data");//获取DataDate date =newDate();String timestamp = String.valueOf(date.getTime()/1000);//将时间戳截取到秒的量级(长度共10位)String key ="a323f9b6-1f04-420e-adb9-b06ty67b0e63";String bsign = AppKey + timestamp + Data + key;//待签名的字符串String sign = DigestUtils.md5Hex(bsign);//签名后的值
将Sign的值和签名时用的TimeStamp更新到body中:
//JSON对象提供put方法,用于更改key的值jso.put("TimeStamp",Integer.parseInt(timestamp));//timestamp的类型是String,这里转成整型jso.put("Sign",sign);body = jso.toString();//把body还原回字符串类型arg_body.setValue(body);//将新body替换到取样器的参数中,实现了截获 → 修改 → 发送修改后的内容
第2种方式
新建 “前置处理器 → 用户参数”,注意要放在beanshell的前面,以便先执行
设置参数名Mobile,参数值如下:
由3部分组成(格式要求 "^1(3|4|5|6|7|8|9)\d{9}$")
即首位数字 “1”
次位数字 ${__Random(3,9,)} :“3~9”随机
其他数字 ${__Random(100000000,999999999,)} :9位数随机
1${__Random(3,9,)}${__Random(100000000,999999999,)}
每次迭代更新一次
修改脚本
修改request body
{"AppKey":"z417App","AppVer":"5.0.4","Data":"{\"Mobile\":\"${Mobile}\",\"PlatType\":101,\"RegSource\":2,}","Lang":"CN","Sign":"${sign}","TimeStamp": ${ts}}
修改beanshell内容
importorg.apache.commons.codec.digest.DigestUtils;importjava.util.Date; Date date =newDate(); String timestamp = String.valueOf(date.getTime()/1000);vars.put("ts",timestamp);String data ="{\"Mobile\":\"${Mobile}\",\"PlatType\":101,\"RegSource\":2,}";String key ="a323f9b6-1f04-420e-adb9-b06ty67b0e63";String bsign ="z417App"+ timestamp + data + key;vars.put("sign",DigestUtils.md5Hex(bsign));