JMeter-SSE响应数据自动化3.0

发布于:2025-06-20 ⋅ 阅读:(21) ⋅ 点赞:(0)

背景

此次因为多了一些需要过滤排除的错误(数量很少),还需要修改下JMeter的jtl文件输出数据(后续统计数据需要)
所以只涉及到JSR脚本的一些改动(此部分改动并不会影响到JMeter的HTML报告)

改动

主要通过设置JMeter中prev输出数据变量threadName为appName这样的方法,来控制jtl的数据。

prev.setThreadName(vars.get(“xxx”) + “^” + vars.get(“xxx”));

脚本如下:
具体改动可以对比自动化2.0

要注意一些响应信息自带的换行符(\n),可能会影响到后续处理jtl文件的数据,目前用的是将\n更换为"-" 或者 “”

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", "");

  // 设置threadName为appName
  prev.setThreadName(vars.get("appName") + "^" + vars.get("xxx"));

}

// 判断是否是流式响应
private Boolean isStreamingResponse(String response) {
  return response.contains("data: {");
}

// 非流式响应处理,即HTTP请求错误处理
private void errorResponse(String response) {
  log.info("进入errorResponse处理!!!");    
      // 判断是不是json格式的响应,first == { ? 是 : 不是
      response = response.replace("\n","");
      String first = response.substring(0,1);
      if("{".equals(first)) {
          // json格式的错误响应
          jsonErrorResponse(response);
      }else {
          // 非json格式的错误响应
          noJsonErrorResponse(response);
      }
}

// json格式的错误响应处理
private void jsonErrorResponse(String response) throws Exception {
  JSONObject jsonResponse = new JSONObject(response);
  String msg = jsonResponse.get("msg");

  if ("智能体不存在".equals(msg)) {
      setAssertMsg("xxx",msg);
  } else {
      setAssertMsg("服务器错误",msg);
  }
}

// 非json格式的错误响应处理
private void noJsonErrorResponse(String response) throws Exception {
  String mainMag = response.substring(0,response.indexOf("at "));
  setAssertMsg("服务器/其他错误",mainMag);
  
}

// 处理SSE响应数据,以data: 为分隔符,输出结果到String[] 中
private String[] splitResponse(String resp) {
 try {
      return resp.split("data: ");
 }catch(Exception e) {
      log.error("拆分resp为String数组失败!xxx:" + 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";
  }
}

// 处理event = error 的响应
private void errorResp(String resp) {
  try{
      JSONObject jsonResponse = new JSONObject(resp);
      String errorMsg = jsonResponse.get("message");
      setAssertMsg("xxx",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("data")
                          .get("outputs")
                          .optString("answer");
  vars.put("response_type","输出结果与预期不符");
  vars.put("actual_msg", answer);
  vars.put("isExist", "false");
}

/**
  正确响应结果
  获取正常响应的最终结果,并设置到ResponseMessage,以供后续使用
*/
private void setTrueResp(String resp){
  //获取answer中的信息,实际msg
  JSONObject jsonResp = new JSONObject(resp);
  String answer = jsonResp.get("data")
                          .get("outputs")
                          .optString("answer");
  String s = answer.replace("\n","-");
  prev.setResponseMessage(s);
  vars.put("isExist", "true");

}

// 是否需要判断 特定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("过滤器失效!","xxx");
      log.warn("过滤白名单失败!");
  }
}

/**
  每次执行后,处理变量
  避免下次空变量的值 受上次的影响
  变量:mustParam
*/
private void afterHandle(){
  vars.put("mustParam","");
  vars.put("target","");
}


SampleResult prev = ctx.getPreviousResult();

String response = prev.getResponseDataAsString();

// 执行前重置变量
init();

// 判断是不是SSE响应
try {
  if (!isStreamingResponse(response)) {
      // 非SSE响应
      errorResponse(response);
  } else {
      // SSE响应
      // 拆分
      String[] respArray = splitResponse(response);
      // 获取event,进行判断
      String event = getEvent(respArray[respArray.length - 1]);
      if("message_end".equals(event)) {
          // 没有错误,判断 workflow_finished 响应中含有目标字段
          if(needCheckTarget(respArray[respArray.length - 2])){
              setTrueResp(respArray[respArray.length - 2]);
          }else {
              // 无目标字段,更新断言信息
              setAssertMsg(respArray[respArray.length - 2]);
          }
      }else if("error".equals(event)) {
          // 有报错,进入过滤器,过滤白名单
          filter(respArray[respArray.length - 1]);
      }else if("Unknow".equals(event)) {
          // 获取event的字段内容失败!
          setAssertMsg("xxx","xxx");
      }else {
          // 未知错误
          setAssertMsg("xxx!","xxx");
      }
  }
} catch (Exception e) {
  log.error("处理响应失败!", e);
  setAssertMsg("xxx!","xxx");
  prev.setSuccessful(false);
}finally {
  afterHandle();
}

网站公告

今日签到

点亮在社区的每一天
去签到