You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JMeter分块上传文件:能否用内存文件变量替代本地文件路径?

JMeter分块上传文件:如何用内存文件替代物理文件路径?

问题描述

我正在编写JMeter测试计划,实现分块向服务器上传文件,但Java知识有限。目前我结合While控制器和BeanShell预处理器,写了从文件读取字节块的脚本,但遇到一个问题:HTTP请求采样器的文件上传区域要求填写物理文件路径,我想知道能不能在BeanShell预处理器中创建内存文件,然后把这个内存文件的变量用到文件路径字段里?

我觉得理论上是可行的,毕竟文件上传时本来也是先加载到内存再发送给服务器。有没有办法从1MB大小的字节块创建内存文件,然后作为上传文件使用?

附上我当前的BeanShell预处理器代码:

Integer maxChunkSize = new Integer(vars.get("FILE_MAX_SIZE"));
String uploadFilePath = vars.get("UPLOAD_FILE");
uploadFileSize = new File(uploadFilePath).length();
InputStream uploadFile = new BufferedInputStream(new FileInputStream(uploadFilePath));
int offset = whileCounter * maxChunkSize;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] bytes;
int size;
/* creating bytes array to hold file data*/
if (offset < uploadFileSize) {
    if (((int) offset + (int) maxChunkSize) < uploadFileSize) {
        bytes = new byte[ (int) maxChunkSize];
        size = maxChunkSize;
    } else {
        size = (int) (uploadFileSize - offset);
        bytes = new byte[ (int) size];
        vars.put("WHILE_LOOP", "0");
    }
}
/* printing results for debugging */
/* log.info(" ============================================================== ");
log.info("While counter " + whileCounter.toString() );
log.info("While loop " + vars.get("WHILE_LOOP").toString() );
log.info("The file to upload is : " + uploadFilePath);
log.info("Maximum Chunk size is : " + maxChunkSize.toString());
log.info("Current Offset is : " + offset.toString());
log.info("The file size is " + uploadFileSize.toString());
log.info(" ============================================================== "); */
/* here it is giving method invocation on loop counter 2, so skip method is used */
uploadFile.skip(offset);
int bytesRead = uploadFile.read(bytes, 0, size);
/* write to byte output stream to read as a file */
bos.write(bytes, 0, bytesRead);
/* params for next iteration */
uploadFile.close();
whileCounter++;
vars.put("WHILE_COUNTER", whileCounter.toString() );

我需要两种方向的帮助:要么是JMeter分块上传文件的替代方案,要么是实现能在HTTP请求采样器文件上传区域使用的内存文件变量的方法。


解决方案

方案一:用JSR223预处理器直接构造Multipart请求(推荐)

HTTP请求采样器的文件上传字段确实只认物理文件路径,但我们可以绕过这个限制——直接在JSR223预处理器中构造完整的Multipart/form-data请求体,完全替代采样器的自动参数处理。

具体步骤:

  1. 配置HTTP请求采样器:
    • 请求方法设为POST
    • 切换到「高级」标签页,勾选「使用multipart/form-data」和「禁用自动编码」
    • 不要填写文件上传区域的任何内容
  2. 添加JSR223预处理器,选择Groovy语言(性能远优于BeanShell),写入以下脚本:
def maxChunkSize = Integer.parseInt(vars.get("FILE_MAX_SIZE"))
def uploadFilePath = vars.get("UPLOAD_FILE")
def uploadFile = new File(uploadFilePath)
def fileSize = uploadFile.length()
def whileCounter = Integer.parseInt(vars.getOrDefault("WHILE_COUNTER", "0"))
def offset = whileCounter * maxChunkSize

// 计算当前块的实际大小
def chunkSize = (offset + maxChunkSize) < fileSize ? maxChunkSize : (fileSize - offset)
if (chunkSize <= 0) {
    vars.put("WHILE_LOOP", "0")
    return
}

// 读取当前块的字节数据
def bytes = new byte[chunkSize as int]
def inputStream = new BufferedInputStream(new FileInputStream(uploadFile))
inputStream.skip(offset)
inputStream.read(bytes, 0, chunkSize as int)
inputStream.close()

// 生成Multipart边界(避免与内容冲突)
def boundary = "----WebKitFormBoundary${UUID.randomUUID()}"
sampler.getArguments().clear()

// 拼接请求体头部
def headerPart = new StringBuilder()
headerPart.append("--").append(boundary).append("\r\n")
headerPart.append("Content-Disposition: form-data; name=\"file\"; filename=\"").append(uploadFile.getName()).append("\"\r\n")
headerPart.append("Content-Type: application/octet-stream\r\n\r\n")

// 将头部、字节数据、尾部加入请求参数
sampler.getArguments().addArgument("", headerPart.toString(), null)
sampler.getArguments().addArgument("", new String(bytes, "ISO-8859-1"), null)
sampler.getArguments().addArgument("", "\r\n--" + boundary + "--\r\n", null)

// 设置请求头的Content-Type
sampler.getHeaderManager().add("Content-Type", "multipart/form-data; boundary=" + boundary)

// 更新循环计数器
whileCounter++
vars.put("WHILE_COUNTER", whileCounter.toString())
  1. 配置While控制器的条件为${WHILE_LOOP} == "1"(测试前记得初始化WHILE_LOOP变量为"1")

方案二:临时文件替代内存文件(简单易上手)

如果不想直接构造请求体,也可以把读取到的字节块写入临时文件,再把临时文件路径传给HTTP请求采样器。

修改你的BeanShell脚本,在末尾添加写入临时文件的代码:

// 保留你原来的所有代码...

// 将字节流写入临时文件
File tempFile = File.createTempFile("upload_chunk_", ".tmp");
FileOutputStream fos = new FileOutputStream(tempFile);
bos.writeTo(fos);
fos.close();
bos.close();

// 把临时文件路径存入变量,供HTTP请求采样器使用
vars.put("CHUNK_FILE_PATH", tempFile.getAbsolutePath());

// 可选:添加TearDown线程组,在测试结束后清理临时文件
// 可以在TearDown中执行 new File(vars.get("CHUNK_FILE_PATH")).delete();

之后在HTTP请求采样器的文件上传区域,直接填写${CHUNK_FILE_PATH}作为文件路径即可。


额外提示

  • 优先用JSR223+Groovy替代BeanShell:Groovy性能更高,语法更灵活,对Java新特性支持更好。
  • 分块上传时记得给服务器传递分块标识:比如添加Content-Range请求头,或者自定义Chunk-Index、Total-Chunks等字段,否则服务器无法拼接完整文件。
  • 添加响应断言:验证每块上传后的服务器返回结果,避免出现丢块或上传失败的情况。

内容的提问来源于stack exchange,提问作者shantanu sharma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 09:18:23