结构图

背景
对之前的脚本进行优化
主要是做一些兼容性处理,降低耦合度
优化内容
1.csv文件变量
增加了白名单变量,目标值变量,必须参数变量
2.响应信息获取方式更新
之前是用正则来捕获简单的json格式的响应,响应的格式是固定的。此次更新后使用的是String的spilt()方法来进行信息截取,易读性相较于正则表达式稍好一些
3.白名单变量初始化
只在线程组的第一次HTTP请求的预处理程序中更新
4.降低JSR223后置处理脚本的耦合度
便于后续维护或者更新,兼容性更好
实现思路
只写了一些更新的结构
1.While控制器

来控制从csv数据中读取数据
2.csv数据文件设置
更新了一些新添加的变量
3.JSR223预处理程序

根据csv文件的数据来更新一些HTTP请求中的参数,比如文件、入参等...
java
import org.json.JSONObject;
import org.json.JSONArray;
import java.util.ArrayList;
//判断是否需要 files 参数
private Boolean needFiles(String str) {
if("1".equals(str)) {
return true;
}else {
return false;
}
}
//设置 files 参数
private void setFiles(String fileParams) {
try{
String[] fileList = fileParams.split(";");
// 创建 JSON 对象数组(List<Map> 格式)
JSONArray fileParamsArray = new JSONArray();
for(String s : fileList) {
fileParamsArray.put(setOneFileParam(s));
}
// 存入 vars(JSON 字符串)
vars.put("fileParam", fileParamsArray.toString());
} catch (Exception e) {
log.error("设置 files 参数 失败!", e);
prev.setSuccessful(false);
}
}
//设置 一个 files 参数
private JSONObject setOneFileParam(String fileParam) {
try {
//将fileParams转为json格式
JSONObject jsonResponse = new JSONObject(fileParam);
// 提取各个参数
String filexxx= jsonResponse.optString("filexxx", "");
String filexxx= jsonResponse.optString("filexxx", "");
Integer filexxx= jsonResponse.optInt("filexxx", 0); // Integer类型
String filexxx= jsonResponse.optString("filexxx", "");
String filexxx= jsonResponse.optString("filexxx", "");
JSONObject fileObj = new JSONObject();
fileObj.put("filexxx", filename);
fileObj.put("filexxx", fileHash);
fileObj.put("filexxx", filesize);
fileObj.put("filexxx", extension);
fileObj.put("filexxx", mimeType);
return fileObj;
}catch (Exception e) {
log.error("setOneFileParam函数设置单个 file 参数 失败!", e);
prev.setSuccessful(false);
}
}
//初始化白名单
private void initWhite() {
try {
String white = vars.get("white");
if(white != null && !"".equals(vars.get("white"))) {
String list = vars.get("white");
String[] ret = list.split(";");
Set<String> whiteSet = new HashSet<String>();
for(String x:ret) {
whiteSet.add(x);
}
vars.putObject("whiteSet",whiteSet);
}
// 使用后重置白名单变量,避免影响后续
vars.put("white","");
}catch (Exception e) {
log.error("初始化白名单失败!");
}
}
try {
String str = vars.get("needFiles");
String fileParams = vars.get("file");
if(needFiles(str)){
//需要文件参数
setFiles(fileParams);
}else{
//不需要文件参数,设置为空
JSONArray fileParamsArray = new JSONArray();
vars.put("fileParam",fileParamsArray.toString());
}
//初始化白名单
initWhite();
} catch (Exception e) {
log.error("判断是否需要文件参数 失败!", e);
prev.setSuccessful(false);
}
4.JSR223后置处理脚本

主要处理响应的信息来进行断言操作
java
import org.apache.jmeter.samplers.SampleResult;
import org.json.JSONObject;
import org.json.JSONException;
// 每次脚本执行前需要重置的变量
private void init(){
// 添加APPID信息
vars.put("APPID",vars.get("appId"));
// 每次重置isExist的值,避免上次结果影响本次
vars.put("isExist", "true");
// 每次重置断言输出信息
vars.put("response_type","");
vars.put("error_msg", "");
vars.put("actual_msg", "");
}
// 判断是否是流式响应
private Boolean isStreamingResponse(String response) {
return response.contains("data: {");
}
// 非流式响应处理
private void handleNonStreamingResponse(String response, SampleResult prev) throws Exception {
JSONObject jsonResponse = new JSONObject(response);
String msg = jsonResponse.get("msg");
if ("不存在".equals(msg)) {
setAssertMsg("不存在",msg);
} else {
setAssertMsg("非流式响应,未知错误",msg);
}
}
// 处理SSE响应数据,以data: 为分隔符,输出结果到String[] 中
private String[] splitResponse(String resp) {
try {
return resp.split("data: ");
}catch(Exception e) {
log.error("拆分resp为String数组失败!" + vars.get("appName"));
}
}
// 获取event信息
private String getEvent(String resp) {
try {
String ret = resp.substring(resp.indexOf("\"", 8)+1, resp.indexOf("\"", 12));
return ret;
}catch(Exception e) {
log.error("获取event的字段内容失败!");
return "Unknow";
}
}
// 处理error响应
private void errorResp(String resp) {
try{
JSONObject jsonResponse = new JSONObject(resp);
String errorMsg = jsonResponse.get("message");
setAssertMsg("执行失败",errorMsg);
}catch(Exception e) {
log.error("处理 error 响应信息失败");
}
}
// 判断有无特定target
private Boolean hasTarget(String resp) {
String targetStr = vars.get("target");
// 每次执行后重置target,避免影响下次target的值
vars.put("target", "");
return resp.contains(targetStr);
}
// 断言参数设置
private void setAssertMsg(String response_type,String error_msg){
vars.put("response_type",response_type);
vars.put("error_msg", error_msg);
vars.put("isExist", "false");
}
private void setAssertMsg(String resp){
//获取answer中的信息,实际msg
JSONObject jsonResp = new JSONObject(resp);
String answer = jsonResp.get("xxx")
.get("xxx")
.optString("具体信息");
vars.put("response_type","无目标值");
vars.put("actual_msg", answer);
vars.put("isExist", "false");
}
// 是否需要判断 特定target
private Boolean needCheckTarget(String resp) {
if(vars.get("target") != null || !"".equals(vars.get("target"))) {
// 有target,需要判断特定target
return hasTarget(resp);
}else {
// 无需判断特定target
return true;
}
}
// 过滤器,过滤白名单
private void filter(String resp) {
try {
Set<String> whiteSet = vars.getObject("whiteSet");
String appId = vars.get("APPID");
if(whiteSet.contains(appId)) {
vars.put("isExist", "true");
}else {
// 非白名单
errorResp(resp);
}
} catch (Exception e) {
setAssertMsg("过滤器失效!","过滤器失效!");
log.warn("过滤白名单失败!");
}
}
/**
每次执行后,处理变量
避免下次空变量的值 受上次的影响
变量:xxx
*/
private void afterHandle(){
vars.put("xxx","");
}
SampleResult prev = ctx.getPreviousResult();
String response = prev.getResponseDataAsString();
// 执行前重置变量
init();
// 判断是不是SSE响应
try {
if (!isStreamingResponse(response)) {
// 非SSE响应
handleNonStreamingResponse(response, prev);
} else {
// SSE响应
// 拆分
String[] respArray = splitResponse(response);
// 获取event,进行判断
String event = getEvent(respArray[respArray.length - 1]);
if("message_end".equals(event)) {
if(needCheckTarget(respArray[respArray.length - 2])){
vars.put("isExist", "true");
}else {
// 无目标字段,更新断言信息
setAssertMsg(respArray[respArray.length - 2]);
}
}else if("error".equals(event)) {
// 有报错,进入过滤器,过滤白名单
filter(respArray[respArray.length - 1]);
}else if("Unknow".equals(event)) {
// 获取event的字段内容失败!
setAssertMsg("响应异常!","获取event的字段内容失败!");
}else {
// 未知错误
setAssertMsg("处理SSE响应异常!!!","处理SSE响应异常!!!");
}
}
} catch (Exception e) {
log.error("处理响应失败!", e);
setAssertMsg("处理响应异常!","处理响应异常!");
prev.setSuccessful(false);
}finally {
afterHandle();
}