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:\DownLoad\Software\apache-jmeter-3.1\lib\ext
    

來看看如何截獲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. 歡迎交流指正


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM