接口Common Header
注意不要再加雙引號了,默認就是string

image.png
通用變量定義:

image.png
接口請求中引用定義的變量

image.png
BeanShell 增加簽名
前提條件,需要增加對應的jar包到JMeter lib 目錄, 并在對應位置增加相關引入

image.png
BeanShell 腳本程序如下,由于BeanShell只支持java1.5,泛型等無法支持,因此使用Groovy語法

image.png
import org.apache.jmeter.config.Arguments
import org.apache.jmeter.protocol.http.control.HeaderManager
import org.apache.jmeter.protocol.http.control.Header
import org.apache.jmeter.protocol.http.util.HTTPArgument
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase
import org.bouncycastle.asn1.gm.GMNamedCurves
import org.bouncycastle.asn1.x9.X9ECParameters
import org.bouncycastle.crypto.digests.SM3Digest
import org.bouncycastle.crypto.engines.SM2Engine
import org.bouncycastle.crypto.macs.HMac
import org.bouncycastle.crypto.params.ECDomainParameters
import org.bouncycastle.crypto.params.ECPrivateKeyParameters
import org.bouncycastle.crypto.params.KeyParameter
import org.bouncycastle.util.encoders.Hex
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import java.lang.reflect.Type
import java.io.IOException
import java.util.ArrayList
import java.util.Collections
import java.util.HashMap
import java.util.LinkedHashMap
import java.util.List
import java.util.Map
import java.util.Set
import java.util.TreeMap
import groovy.json.JsonSlurper
import groovy.json.JsonOutput
def getSM3hmac(String srcData) {
String secret = "60V97AD18OC1JUIJVV7P9FIRR069F769FI8R"
byte[] key = secret.bytes
byte[] src = srcData.bytes
KeyParameter keyParameter = new KeyParameter(key)
SM3Digest digest = new SM3Digest()
HMac mac = new HMac(digest)
mac.init(keyParameter)
mac.update(src, 0, src.length)
byte[] encode = new byte[mac.getMacSize()]
mac.doFinal(encode, 0)
String result = Hex.toHexString(encode)
return result
}
def sortJsonByKeys(Map jsonMap) {
// 獲取鍵列表并排序
def sortedKeys = jsonMap.keySet().toList().sort()
// 創(chuàng)建一個新的LinkedHashMap以保持鍵的順序
def sortedMap = new LinkedHashMap<>()
sortedKeys.each { key ->
sortedMap.put(key, jsonMap.get(key))
}
// 將排序后的Map轉換回JSON字符串
def sortJsonStr = JsonOutput.toJson(sortedMap)
if (null == sortJsonStr || sortJsonStr.equals("{}") || sortMap.isEmpty()) {
sortJsonStr = "";
}
return sortJsonStr
}
// 獲取當前日期
log.info("獲取日期。。。。。。")
String timestamp = System.currentTimeMillis().toString()
log.info("getCurrent:{}", timestamp)
// 開始處理
log.info("接口調用前置處理器-簽名/加密相關處理")
Arguments args = sampler.getArguments()
// 獲取請求路徑
String path = sampler.getPath()
log.info("獲取請求路徑:{}", path)
String host = sampler.getDomain()
log.info("獲取host:{}", host)
// 獲取協(xié)議
String protocol = sampler.getProtocol()
log.info("獲取協(xié)議:{}", protocol)
// 拼接URL
String requestUrl = "${protocol}://${host}${path}"
log.info("拼接URL:{}", requestUrl)
// 獲取請求方法返回值為大寫GET
String method = sampler.getMethod().toUpperCase()
log.info("獲取請求方法返回值為大寫:{}", method)
HeaderManager headerManager = sampler.getHeaderManager()
if (headerManager != null) {
for (int i = 0; i < headerManager.size(); i++) {
Header header = headerManager.get(i)
log.info("${header.getName()} : ${header.getValue()}")
}
}
String sortBody = ""
if (method.equals("POST")) {
// 獲取請求參數(shù)
String body = args.getArgument(0) ?.getValue()
log.info("業(yè)務參數(shù)Post:{}", body)
def jsonMap = new JsonSlurper().parseText(body)
sortBody = sortJsonByKeys(jsonMap).replace("\n", "").replace(" ", "")
log.info("業(yè)務參數(shù)Post sortBody:{}", sortBody)
//args.getArgument(0)?.setValue(sortBody)
} else {
//獲取請求參數(shù)
int n = args.getArgumentCount();
log.info("業(yè)務參數(shù)Get 參數(shù)數(shù)量:{}", n)
Map<String, Object> parmMap = new TreeMap<>();
for(int i =0;i<n;i++){
String name = args.getArgument(i).getName()
def value = args.getArgument(i).getValue()
log.info("業(yè)務參數(shù)Get 參數(shù):{}",name+":"+value )
parmMap.put(name, value);
}
sortBody= sortJsonByKeys(parmMap).replace("\n", "").replace(" ", "")
log.info("業(yè)務參數(shù)Get sortBody:{}", sortBody)
}
String payload = sortBody
String[] split = path.split("/")
String urlSuffix = split[-1]
log.info("Url 后綴:{}", urlSuffix)
String source = "${urlSuffix}${timestamp}CARSERVICE${payload}"
log.info("加密之前數(shù)據(jù)source:{}", source)
String result = getSM3hmac(source)
log.info("加密之后數(shù)據(jù)result:{}", result)
// 新建一個Header對象
Header myHeader = new Header("sign", result)
// 添加Header到請求頭管理器
headerManager.add(myHeader)
Header sourceHeader = new Header("signSource", source);
// 添加Header到請求頭管理器
headerManager.add(sourceHeader);
Header time = new Header("timeStamp", timestamp);
// 添加Header到請求頭管理器
headerManager.add(time);
BeanShell 后置腳本
前提條件需要將JMeter中
jmeter.properties文件,添加如下設置:security.manager.enabled=false(之前排查了好久) ,不然無法調起cmd,使用Cmd執(zhí)行Python文件,生成二維碼,同時引入FastJson
import java.io.BufferedReader;
import java.io.InputStreamReader;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
String statusCode = prev.getResponseCode(); //獲取響應代碼
log.info("statusCode {}",statusCode);
String response_headers = prev.getResponseHeaders(); //獲取響應頭
log.info("response_headers {}",response_headers);
String response_reason = prev.getResponseMessage(); //獲取響應信息
log.info("response_reason {}",response_reason);
// 獲取響應數(shù)據(jù)
String responseData = prev.getResponseDataAsString();
log.info("responseData {}",responseData);
JSONObject data = JSON.parseObject(responseData);
JSONObject data1 = (JSONObject) data.get("data");
String qrCode = data1.getString("qrCode");
log.info("qrCode {}",qrCode);
// cmd 特殊符合需要轉義
qrCode=qrCode.replace("&","^&");
String command = "cmd /c python D:\\APP\\apache-jmeter-5.6.3\\case\\python\\showQrcode.py --t "+qrCode;
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec(command);
pr.waitFor();
BufferedReader b = new BufferedReader(new InputStreamReader(pr.getInputStream()));
String line = "";
StringBuilder response = new StringBuilder();
while ((line = b.readLine()) != null) {
response.append(line);
}
String response_data = response.toString();
System.out.println("二維碼結果:"+response_data);
b.close();
生成二維碼,
對應的Python3腳本文件
import argparse
import qrcode as qrcode
import matplotlib.pyplot as plt
filename = '二維碼.png'
# 獲取二維碼
def make_qr_code():
# 接收cmd命令里面的參數(shù)
parse = argparse.ArgumentParser()
parse.add_argument("--t", type=str, default = None)
args = parse.parse_args()
content = args.t
print("generate content "+content)
q = qrcode.QRCode()
q.add_data(content)
q.make()
img = q.make_image()
img.save(filename)
plt.title = '登錄二維碼'
plt.imshow(img)
plt.show()
print("generate success")
if __name__ == '__main__':
make_qr_code()
接口參數(shù)傳遞,
可以失業(yè)props.put 及get 方法

image.png

image.png
完整demo 參考
【免費】Jmeter使用demo,包含驗簽,參數(shù)透傳,調用python文件等資源-CSDN文庫