• JMeter处理动态的签名内容


    先贴脚本,大神请直取

    • 新建线程组 → http取样器 → 前置处理器 → bean shell 预处理程序
      import org.apache.commons.codec.digest.DigestUtils; 
      import java.util.Date;
      import org.apache.jmeter.config.*; 
      import com.alibaba.fastjson.JSON;          // 文末有fastjson.jar的链接
      import com.alibaba.fastjson.JSONObject;
        
      Arguments args = sampler.getArguments();   // 截获请求,包含url、headers 和 body 三部分
      Argument arg_body = args.getArgument(0);   // 获取请求body
      String 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 = new Date();
      //将时间戳截取到秒的量级(长度共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 字段的值到jsonObject
      jso.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脚本

    import org.apache.commons.codec.digest.DigestUtils;   //里面有md5Hex()方法,返回(32位[大])签名后的内容
    import java.util.Date;                                //里面有生成当前时间戳的方法
    import org.apache.jmeter.config.*;                    //里面有截获request body的方法
    // 以上jar包自带,可放心导入;下面两个来自阿里的fastjson包,文末有下载链接
    import com.alibaba.fastjson.JSON;                     //序列化与反序列化
    import com.alibaba.fastjson.JSONObject;               //创建json对象
    
    • 下载fastjson放到jmeter的plugins专用目录,如我的:

      E:DownLoadSoftwareapache-jmeter-3.1libext
      

    来看看如何截获sampler的请求

    Arguments args = sampler.getArguments();    // 包含url、headers 和 body 三部分
    Argument arg_body = args.getArgument(0);    // 获取request body
    String body = arg_body.getValue();          // 将request body保存成字符串
    log.info(body);                             // 打印下看看,跑压测时勿忘把log注掉
    
    1. Arguments:api文档解释如下 :

      A set of Argument objects. Argument对象的set集合 ,那Argument是什么呢?不慌~
      
    2. sampler:api文档描述如下:

      Common constants and methods for HTTP samplers. HTTP取样器的常用常量和方法。
      
    3. 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.
      
    4. 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.
      
    5. Argument 对象有getValue(),api文档描述如下:

      //大体意思是以字符串类型,返回Argument 对象中属性的值。
      public java.lang.String getValue()
      Gets the value of the Argument object.
      Returns:
          the attribute's value
      
    6. 至此,我们已经把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
    }
    
    1. 确定会动态变化字段,这里有3个:Mobile,Sign,TimeStamp;

    2. Mobile 的值已经用参数化管理起来了;

    3. Sign 的值会因为每次传参的变化而变化,比如每次更新后的 Mobile 的值;

    4. TimeStamp 时间戳,每次请求都不一样。

    大招一开

    1. body是个String类型的json,需要转成json类型:

      JSONObject jso = JSON.parseObject(body);                 //转成json对象
      
    2. 准备签名(Sign)需要的内容并签名,不讲签名知识了,前文有提及:

      String AppKey = jso.getString("AppKey");                 //获取AppKey
      String Data = jso.getString("Data");                     //获取Data
      Date date = new Date();
      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);                 //签名后的值
      
    3. 将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,参数值如下:

        1. 由3部分组成(格式要求 "^1(3|4|5|6|7|8|9)d{9}$")

        2. 即首位数字 “1”

        3. 次位数字 ${__Random(3,9,)} :“3~9”随机

        4. 其他数字 ${__Random(100000000,999999999,)} :9位数随机

          1${__Random(3,9,)}${__Random(100000000,999999999,)}
          
      • 每次迭代更新一次

    • 修改脚本

      1. 修改request body

        {
            "AppKey":"z417App",
            "AppVer":"5.0.4",
            "Data":"{"Mobile":"${Mobile}","PlatType":101,"RegSource":2,}",
            "Lang":"CN",
            "Sign":"${sign}",
            "TimeStamp": ${ts}
        }
        
      2. 修改beanshell内容

        import org.apache.commons.codec.digest.DigestUtils;
        import java.util.Date; 
           
        Date date = new Date(); 
        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));
        

    问题思考

    1. Arguments 和 Argument 到底有什么?哪些常用?

    2. fastjson api.doc链接1.2.47下载链接

    3. bean shell中能完成一次http请求吗?

    4. 欢迎交流指正

  • 相关阅读:
    算法之路 level 01 problem set
    算法原理与实践(链表)
    散列表(HashTable)
    系统设计与实践(实战演练)
    桶排序 + 基数排序
    算法原理与实践(二叉树)
    Total Difference String
    【翻译】std::list::remove
    【翻译】std::remove
    Observer模式实践
  • 原文地址:https://www.cnblogs.com/z417/p/13785978.html
Copyright © 2020-2023  润新知