JMeter-SSE响应数据自动化

结构图

在这里插入图片描述

背景:

需要写一个JMeter脚本来进行自动化测试,主要是通过接口调用一些东西,同时要对响应的数据进行处理,包括不限于错误信息的输出。

1.SSE(摘录)

SSE(Server-Sent Events)是一种基于HTTP协议、允许服务器主动向客户端推送实时更新的技术‌。它特别适用于单向数据流的实时场景,例如消息通知、AI对话流式响应等,通过保持长连接实现持续数据传输。

2.实现思路

2.1 用户自定义变量组件

主要是用来统一更换和维护环境变量的,比如线上、线下环境host的切换

2.2 HTTP信息头管理

设置https请求的信息头,比如token,数据格式等等
在这里插入图片描述

2.3 CSV 数据文件设置

参数如下图设置
在这里插入图片描述
变量名称:appId,query,appName,needFiles,file

对应vars中的变量,变量值是根据分隔带JMeter自动处理的,变量名称 数量和分隔后的变量值 数量不对应也没影响,两者缺少的值会忽略或者设置为空值

2.4 HTTP请求组件

需要设置消息体数据,请求url等
在这里插入图片描述
下面三个插件,归类到HTTP请求的子目录下:如图
在这里插入图片描述

2.4.1 JSR223 预处理程序

主要来处理一下请求中消息体数据中的一个参数,fileParam

根据csv文件中的标记来确定fileParam的具体值,如下代码

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{//将fileParams转为json格式JSONObject jsonResponse = new JSONObject(fileParams);// 提取各个参数String filename = jsonResponse.optString("xxx", "");String fileHash = jsonResponse.optString("xxx", "");Integer filesize = jsonResponse.optInt("xxx", 0);  // Integer类型String extension = jsonResponse.optString("xxx", "");String mimeType = jsonResponse.optString("xxx", "");// 创建 JSON 对象数组(List<Map> 格式)JSONArray fileParamsArray = new JSONArray();JSONObject fileObj = new JSONObject();fileObj.put("xxx", xxx);fileObj.put("xxx", xxx);fileObj.put("xxx", xxx);fileObj.put("xxx", xxx);fileObj.put("xxx", xxx);fileParamsArray.put(fileObj);// 存入 vars(JSON 字符串)vars.put("fileParam", fileParamsArray.toString());} catch (Exception e) {log.error("设置 files 参数 失败!", e);prev.setSuccessful(false);}	}    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());	}
} catch (Exception e) {log.error("判断是否需要文件参数 失败!", e);prev.setSuccessful(false);
}
2.4.2 JSR223 后置处理程序

对SSE响应的数据进行处理和判断,确定好哪个数据是一次请求结束的标记

下面代码是根据 event 含有 message_end 字段来做执行成功的标记
error字段来错失败的标记,同时进入断言

下面的代码是逐行匹配、逐个处理 SSE 事件适合实时响应场景

import org.apache.jmeter.samplers.SampleResult;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import org.json.JSONObject;
import org.json.JSONException;// 判断是否是流式响应
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)) {vars.put("response_type", "智能体不存在");vars.put("error_msg", msg);vars.put("isExist", "false");} else {vars.put("response_type", "非流式响应,未知错误");vars.put("error_msg", msg);vars.put("isExist", "false");}
}// 流式响应处理
private void handleStreamingResponse(String response, SampleResult prev) throws Exception {vars.put("response_type", "streaming");// 正则表达式,确保匹配完整JSONPattern pattern = Pattern.compile("data:\\s*(\\{[^{}]*\\})", Pattern.DOTALL)Matcher matcher = pattern.matcher(response);while (matcher.find()) {try {String eventJson = matcher.group(1).trim();// 处理可能的UTF-8 BOM头if (eventJson.startsWith("\uFEFF")) {eventJson = eventJson.substring(1);}JSONObject jsonResponse = new JSONObject(eventJson);String eventType = jsonResponse.optString("event");if ("message_end".equals(eventType)) {vars.put("response_type", "智能体执行成功");vars.put("error_msg", "智能体执行成功");vars.put("isExist", "true");} else if ("error".equals(eventType)) {              vars.put("response_type", "智能体执行失败");String errorMsg = jsonResponse.get("message");vars.put("error_msg", errorMsg);vars.put("isExist", "false");}} catch (JSONException e) {log.warn("SSE事件JSON解析失败,跳过该事件: " + vars.get("appName"));}}
}SampleResult prev = ctx.getPreviousResult();String response = prev.getResponseDataAsString();//添加APPID信息
vars.put("APPID",vars.get("appId"));//每次重置isExist的值,避免上次结果影响本次
vars.put("isExist", "true");try {if (!isStreamingResponse(response)) {handleNonStreamingResponse(response, prev);} else {handleStreamingResponse(response, prev);}
} catch (Exception e) {log.error("处理响应失败!", e);prev.setSuccessful(false);
}

handleStreamingResponse方法:
对每次符合要求的数据进行处理和判断

// 正则表达式,确保匹配完整JSON
Pattern pattern = Pattern.compile(“data:\s*(\{[^{}]*\})”, Pattern.DOTALL)
Matcher matcher = pattern.matcher(response);

data:\s*
匹配字符串 “data:”,后面跟 0个或多个空白字符(\s* 包括空格、换行符等)。

(\{[^{}]*\})
\{ 匹配左花括号 {({ 需要转义)。
[^{}]* 匹配 任意字符(除了 { 和 })0次或多次,确保匹配的是 单层花括号 的内容。
\} 匹配右花括号 }。
() 表示捕获组,最终提取的是花括号内的内容。

Pattern.DOTALL
让 . 匹配 包括换行符在内的所有字符,确保多行文本也能被正确匹配。
.
Matcher matcher = pattern.matcher(response);
用编译好的正则模式 pattern 去匹配输入的字符串 response。
matcher 对象可以用于查找、提取符合正则规则的部分。

while (matcher.find()) {
try {
String eventJson = matcher.group(1).trim();

matcher.find() 每次找到一个匹配项后,会移动内部指针,直到所有匹配项被遍历完。

matcher.group(1) 提取正则中 第一个捕获组(即 ({[^{}]*}) 匹配的 {…} 部分)。

2.4.3 JSR JSR223 Assertion

进行断言处理,处理需要输出的信息

// 断言
if ("false".equals(vars.get("isExist"))) {// 获取智能体名称String appName = vars.get("appName");// 获取具体失败类型String respone_type = vars.get("response_type");// 获取error_messageString error_message = vars.get("error_msg");// 获取APPIDString appId = vars.get("APPID");//执行失败AssertionResult.setFailure(true); // 标记断言失败AssertionResult.setFailureMessage(appName + "\n\t" + " 智能体ID:" + appId + "\n" + "\t 错误原因:"+ respone_type + "\n" + "\t error_message:" + error_message);// 添加到标签列//prev.setSampleLabel(vars.get("respone_type")) // 修改响应消息为message变量的内容prev.setResponseMessage(respone_type);// 添加调试信息log.info("智能体名称:", appName);log.info("智能体ID:", appId);log.info("错误原因:", respone_type);log.info("error_message:", error_message);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/pingmian/82512.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

<<运算符重载 和 c_str() 的区别和联系

例题 文章开始之前我们看下以下代码&#xff0c;你能精准的说出正确的输出结果并知道其原理吗&#xff1f; void test() {string s1("hello world");cout << s1 << endl;//cout << s1.c_str() << endl;//const char* p1 "xxxx"…

python web flask专题-Flask入门指南:从安装到核心功能详解

Flask入门指南&#xff1a;从安装到核心功能详解 Flask作为Python最流行的轻量级Web框架之一&#xff0c;以其简洁灵活的特性广受开发者喜爱。本文将带你从零开始学习Flask&#xff0c;涵盖安装配置、项目结构、应用实例、路由系统以及请求响应处理等核心知识点。 1. Flask安…

一种C# 的SM4 的 加解密的实现,一般用于医疗或者支付

一种C# 的SM4 的 加解密的实现 一般用于医疗或者支付 加密 string cipherText SM4Helper.Encrypt_test(data, key); public static string Encrypt_test(string plainText, string key) { byte[] keyBytes Encoding.ASCII.GetBytes(key); byte[] input…

“轩辕杯“云盾砺剑CTF挑战赛 Web wp

文章目录 ezflaskezjsezrceezssrf1.0签到ezsql1.0ez_web1非预期预期解 ezflask ssti, 过滤了一些关键词, 绕一下就行 name{{url_for["__globals__"]["__builtins__"]["eval"]("__tropmi__"[::-1])(os)["po""pen"…

Matlab快速上手五十六:详解符号运算里假设的用法,通过假设可以设置符号变量的取值范围,也可以通过假设设置变量属于集合:整数、正数和实数等

1.符号变量中假设的概念 在符号数学工具箱中&#xff0c;符号变量默认范围是全体复数&#xff0c;也就是说&#xff0c;符号运算是在全体复数域进行的&#xff0c;若需要运算中&#xff0c;不使用全体复数域&#xff0c;可以为变量设定取值范围&#xff0c;这就用到了假设&…

【python实用小脚本-79】[HR转型]Excel难民到数据工程师|用Python实现CSV秒转JSON(附HRIS系统对接方案)

场景故事&#xff1a;从手动复制粘贴到自动化数据流转 "Kelly&#xff0c;我们需要把3000名员工的考勤数据导入新HR系统&#xff0c;今天能完成吗&#xff1f;"去年这个时候&#xff0c;作为HRIS项目负责人的我&#xff0c;面对这个需求时第一反应是打开Excel开始手…

数据透视:水安 B 证如何影响水利企业的生存指数?

某大数据公司提取了 3000 家水利企业的经营数据&#xff0c;一组关联分析令人震惊&#xff1a;B 证配备率与企业利润率的相关系数达 0.67—— 这意味着持证率每提升 10%&#xff0c;企业利润率平均提高 4.2 个百分点。当我们用数据解剖这本红本本&#xff0c;会发现它像一根无形…

从零搭建上门做饭平台:高并发订单系统设计

你知道为什么聪明人都在抢着做上门做饭平台吗&#xff1f;因为这可能是餐饮行业最后一片蓝海&#xff01;传统餐饮还在为房租人工发愁时&#xff0c;上门私厨已经轻装上阵杀出重围。不需要门店租金&#xff0c;不用养服务员&#xff0c;厨师直接上门服务&#xff0c;成本直降60…

openpi π₀ 项目部署运行逻辑(四)——机器人主控程序 main.py — aloha_real

π₀ 机器人主控脚本都在 examples 中&#xff1a; 可以看到包含了多种类机器人适配 此笔记首先记录了 aloha_real 部分 aloha_real 中&#xff0c;main.py 是 openpi ALOHA 平台上“主控执行入口”&#xff0c;负责&#xff1a; 建立与推理服务器&#xff08;serve_policy.…

利用 Python 爬虫获取唯品会 VIP 商品详情:实战指南

在当今电商竞争激烈的环境中&#xff0c;VIP 商品往往是商家的核心竞争力所在。这些商品不仅代表着品牌的高端形象&#xff0c;更是吸引高价值客户的关键。因此&#xff0c;获取 VIP 商品的详细信息对于市场分析、竞品研究以及优化自身产品策略至关重要。Python 作为一种强大的…

鸿蒙桌面快捷方式开发

桌面快捷方式开发实战 [参考文档] (https://developer.huawei.com/consumer/cn/doc/best-practices/bpta-desktop-shortcuts) 在module.json5配置文件中的abilities标签下的metadata中设置resource属性值为$profile:shortcuts_config&#xff0c;指定应用的快捷方式配置文件&…

3分钟学会跨浏览器富文本编辑器开发:精准光标定位+内容插入(附完整代码)

一、痛点直击&#xff1a;传统编辑器的三大坑 作为前端开发&#xff0c;你是否遇到过以下灵魂拷问&#xff1f; ✅ 为什么Firefox光标能精准定位&#xff0c;IE却永远跳转到开头&#xff1f;✅ 图片上传后如何保证插入位置不偏移&#xff1f;✅ 跨浏览器兼容测试时&#xff0…

RK3562 Linux-5.10 内核HUSB311 Type-C 控制器芯片调试记录

硬件原理&#xff1a; 1. type C 接口&#xff1a; 1.1 HUSB311芯片&#xff0c; CC1和CC2 逻辑接到HUSB311 上面&#xff0c; 接I2C0组和USBCC_INT_L USBCC_INT_L 接到GPIO0_A6 做为CC的逻辑中断 1.2 TYPEC_DP/TYPEC_DM 接到ARM 端的USB3.0 OTG上面 1.2 TYPEC_RX1P/TYPEC…

深入理解Java中的BigDecimal:高精度计算的核心工具

精心整理了最新的面试资料和简历模板&#xff0c;有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 引言 在Java编程中&#xff0c;处理浮点数运算时可能会遇到精度丢失的问题。例如&#xff1a; System.out.println(0.1 0.2); // 输出&#xff1a;0.30000…

大模型微调(面经总结)

持续更新中 一、LORA篇1、介绍一下Lora的原理2、LoRA 是为了解决什么问题提出的&#xff1f;哪些模型适合用 LoRA 微调&#xff1f;什么是低秩分解&#xff1f;**低秩分解&#xff1a;用小矩阵逼近大矩阵** 3、LoRA初始化4、LoRA初始化秩 r 是怎么选的&#xff1f;为什么不选其…

Camera相机人脸识别系列专题分析之一:人脸识别系列专题SOP及理论知识介绍

【关注我&#xff0c;后续持续新增专题博文&#xff0c;谢谢&#xff01;&#xff01;&#xff01;】 上一篇我们讲了&#xff1a;内存泄漏和内存占用拆解系列专题 这一篇我们开始讲&#xff1a; Camera相机人脸识别系列专题分析之一&#xff1a;人脸识别系列专题SOP及理论知识…

【Elasticsearch】PUT` 请求覆盖式更新

是的&#xff0c;Elasticsearch 中的 PUT 请求是覆盖式的。当你使用 PUT 请求向索引中写入文档时&#xff0c;如果文档已经存在&#xff0c;Elasticsearch 会完全替换整个文档的内容&#xff0c;而不是进行部分更新。 覆盖式的具体行为 - 文档存在时&#xff1a;PUT 请求会用新…

计算机系统结构-第4章-数据级并行

数据集并行的概念: 并行场景1: 对不同数据执行相同的操作: 串行执行: 可以同时进行: 可以尝试一个多条指令,多核执行 引入: SISD: 单核,单线程,串行执行,这样耗时 MIMD: 多核,多线程,并行执行,一条指令多次重复,变成了MIMID 存在的问题: 在标量CPU流水线中&#xff0…

重新安装解决mac vscode点击不能跳转问题

依次执行以下过程 删除vscode程序 删除vscode的缓存文件夹(xxx表示你的用户名) /Users/xxx/Library/Application Support/Code 重新安装vscode 这时候你会反向可以跳转项目内的import 文件以及自定义函数。但是import安装的包还不能点击跳转 配置python环境 如果你电脑没有安…

题目 3334: 蓝桥杯2025年第十六届省赛真题-园艺

题目 3334: 蓝桥杯2025年第十六届省赛真题-园艺 时间限制: 2s 内存限制: 192MB 提交: 129 解决: 37 题目描述 小蓝从左到右种了 n 棵小树&#xff0c;第 i 棵树的高度为 hi &#xff0c;相邻树的间隔相同。 小蓝想挪走一些树使得剩下的树等间隔分布&#xff0c;且从左到右高度逐…