Jmeter+OCRserver,解决图形验证码问题,并举例
当前测试的场景是,某接口,需要主管复核之后,才能提交请求。最后需要最终请求的接口外层套上if控制器,这样就可以只有复核通过时再调用该接口。但ocr识别可能不准确,这样复核接口失败,就不需要再调用下一个接口。二、Jmeter获取验证码,并通过OCRserver识别。4、创建新的http请求,用来调用OCRserver服务。并且使用后置处理器的json提取器获取到识别出的验证码。OCRserver启动
一、先从网上下载一个OCRserver
网上很多,找到一个能用的就行
后面Jmeter调用的时候要保证OCRserver处于运行状态
OCRserver启动后,ip和端口是固定的

二、Jmeter获取验证码,并通过OCRserver识别
可以用如下结构形式

1、获取验证码
这个按照实际调用的验证码接口即可

2、保存相应结果到文件

另:还有一种情况,虽然是图片验证码,但因为前端框架原因,返回结果不是图片,而是二进制信息,这时候就需要,把二进制图片保存为图片
使用JSR223后置处理器

import java.io.FileOutputStream
import java.text.SimpleDateFormat
// 获取接口的二进制响应数据(图片原始数据)
byte[] imageData = prev.getResponseData()
// 生成唯一的文件名(时间戳+随机数避免重复)
def timestamp = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date())
def random = (int)(Math.random() * 1000)
def fileName = "captcha_${timestamp}_${random}.png"
// 定义保存路径(可根据需要修改,例如"./captcha/"表示当前目录下的captcha文件夹)
def savePath = "写一个保存路径"
// 创建完整的文件对象
def file = new File(savePath + fileName)
// 确保目录存在,如果不存在则创建
file.getParentFile().mkdirs()
try {
// 写入图片数据到文件
FileOutputStream fos = new FileOutputStream(file)
fos.write(imageData)
fos.close()
// 获取文件全路径
def fullPath = file.getAbsolutePath()
// 将全路径存入cap变量,供后续步骤使用
vars.put("cap", fullPath)
log.info("验证码图片保存成功:${fullPath}")
log.info("已将路径存入cap变量:${vars.get('cap')}")
} catch (Exception e) {
log.error("验证码图片保存失败:${e.getMessage()}")
// 出错时可以设置一个空值或标记
vars.put("cap", "")
}
3、将保存的图片转换成base64,使用JSR223Sampler
语言选择groovy
import java.io.*;
import org.apache.commons.codec.binary.Base64;
// 取保存响应到文件中的验证码变量结果
String imagePath = vars.get("cap");
// 检查变量是否存在且不为空
if (imagePath == null || imagePath.trim().isEmpty()) {
log.error("变量 'cap' 未设置或为空值");
// 可以设置一个默认路径或者直接返回
return;
}
byte[] data = null;
try {
// 检查文件是否存在
File imageFile = new File(imagePath);
if (!imageFile.exists()) {
log.error("文件不存在: " + imagePath);
return;
}
InputStream in = new FileInputStream(imageFile);
data = new byte[in.available()];
in.read(data);
in.close();
Base64 base64 = new Base64();
vars.put("base64", base64.encodeToString(data));
log.info("成功将文件转换为Base64编码: " + imagePath);
} catch (IOException e) {
log.error("处理文件时发生错误: " + e.getMessage());
e.printStackTrace();
}
4、创建新的http请求,用来调用OCRserver服务

并且使用后置处理器的json提取器获取到识别出的验证码

拿到验证码之后就可以进行使用了
三、使用样例
当前测试的场景是,某接口,需要主管复核之后,才能提交请求。图形验证码是用在复核接口。
但ocr识别可能不准确,这样复核接口失败,就不需要再调用下一个接口
因此使用的结构是这样的

使用while循环,只有符合通过才跳出循环

${__jexl3(vars.get("should_retry") == "true",)}
先定义重试标志

在while循环前增加重置标志的逻辑

String should_retry = vars.get("should_retry");
String terminate = vars.get("terminate");
//log.info('----------------------------------------------')
//log.info('重置前should_retry:'+should_retry);
//log.info('重置前terminate:'+terminate);
// 重置状态变量
vars.put("should_retry", "true")
vars.put("terminate", "false")
// 打印时直接从vars获取最新值,而不是用之前的局部变量
//log.info('重置后should_retry:'+vars.get("should_retry"));
//log.info('重置后terminate:'+vars.get("terminate"));
//log.info('----------------------------------------------')
由于接口会返回以下几个场景
- 复核成功
- 验证码错误
- 其他错误
所以需要区分判断

// 获取提取的返回码(此处code/desc是局部变量,后续未修改,无需调整)
String code = vars.get("responseCode");
String desc = vars.get("responseDesc");
// 注意:此处should_retry/terminate是局部变量,仅用于存储初始值(若后续不打印初始值,甚至可省略这两行)
//String should_retry_init = vars.get("should_retry");
//String terminate_init = vars.get("terminate");
//log.info('----------------------------------------------')
//log.info('复核接口调用前should_retry:'+should_retry_init); // 打印初始值(可选)
//log.info('复核接口调用前terminate:'+terminate_init); // 打印初始值(可选)
//log.info('复核接口调用后responseCode:'+code);
//log.info('复核接口调用后responseDesc:'+desc);
if ("0000".equals(code)) {
// 成功 - 继续后续接口
log.info('复核成功 - 继续后续接口')
vars.put("should_retry", "false")
vars.put("terminate", "false")
} else if ("9999".equals(code) && desc.contains("验证码失效或错误请点击验证码重新获取")) {
// 特定失败 - 需要重试
log.info('特定失败 - 需要重试')
vars.put("should_retry", "true")
vars.put("terminate", "false")
} else {
// 其他错误 - 终止测试
log.info('其他错误 - 终止测试')
vars.put("should_retry", "false")
vars.put("terminate", "true")
}
// 关键修复:从vars中获取修改后的最新值,而非使用局部变量
//log.info('复核接口调用后should_retry:'+vars.get("should_retry"));
//log.info('复核接口调用后terminate:'+vars.get("terminate"));
//log.info('----------------------------------------------')
最后需要最终请求的接口外层套上if控制器,这样就可以只有复核通过时再调用该接口

${__jexl3("${should_retry}" == "false" && "${terminate}" == "false")}
网易易盾是国内领先的数字内容风控服务商,依托网易二十余年的先进技术和一线实践经验沉淀,为客户提供专业可靠的安全服务,涵盖内容安全、业务安全、应用安全、安全专家服务四大领域,全方位保障客户业务合规、稳健和安全运营。
更多推荐



所有评论(0)