- 性能测试
- 接口测试
- CLI
【免费下载链接】artillery
The complete load testing platform. Everything you need for production-grade load tests. Serverless & distributed. Load test with Playwright. Load test HTTP APIs, GraphQL, WebSocket, and more. Use any Node.js module.
本指南以 Artillery 仓库中的 http-file-uploads 示例 为核心,讲解如何在 Artillery 测试脚本中通过formData与fromFile完成 multipart/form-data 文件上传的压测,包括配套 Express 文件接收服务器的搭建、测试脚本编写、随机文件轮换、上传文件清理以及底层源码实现原理。读完本文,你将能够独立编写并运行一个可复用的 HTTP 文件上传负载测试场景。
示例整体结构
该示例位于仓库的 examples/http-file-uploads 目录,包含四个核心组成部分:
| 文件 | 作用 |
|---|---|
app.js | 基于 Express + Multer 的文件上传接收服务器(监听 3000 端口) |
file-uploads.yml | Artillery 测试脚本,演示如何上传文件 |
files/ | 存放待上传的样例文件(jpg / pdf / png 各一个) |
uploads/ | 服务器接收上传后存储文件的目录(运行时生成) |
package.json | 定义服务器启动、测试运行、上传目录清理等 npm 脚本 |
搭建并启动文件接收服务器
安装依赖
示例自带了 Express 应用(app.js),先安装其依赖:
npm install安装完成后启动 HTTP 服务器:
npm run app:start该命令实际执行node app.js(见 package.json 中的scripts定义),启动后服务监听于http://localhost:3000/。
服务器实现解析
接收端服务器代码非常精简,使用 multer 中间件处理 multipart 文件上传:
const express = require('express'); const app = express(); const upload = require('multer')({ dest: 'uploads/', preservePath: true }); const port = 3000; app.post('/upload', upload.single('document'), (req, res) => { const { originalname, mimetype, size } = req.file; res.json({ originalname, mimetype, size }); }); app.listen(port, () => { console.log(`App listening at http://localhost:${port}`); });关键点:
- Multer 将上传文件落盘到
uploads/目录; - 路由
/upload接收字段名为document的单个文件(upload.single('document')),与测试脚本中formData.document.fromFile的字段名一一对应; - 服务器响应返回
originalname、mimetype、size三个 JSON 字段,方便在压测脚本中通过capture断言上传是否成功。
编写文件上传测试脚本
示例测试脚本 file-uploads.yml 是理解 Artillery 文件上传用法的核心:
config: target: "http://localhost:3000" phases: - duration: 10min arrivalRate: 25 # 通过 variables 定义待上传文件的文件名列表, # 这些文件放置在 /files 目录下。 variables: filename: - "artillery-logo.jpg" - "artillery-installation.pdf" - "sre-fundamental-rules.png" scenarios: - flow: # HTTP 服务器有一个 POST /upload 端点,通过 document 字段接收文件 - post: url: "/upload" formData: document: # fromFile 属性指示 Artillery 上传指定文件; # 若文件无法读取,场景会报 ENOENT 错误。 fromFile: "./files/{{ filename }}"该脚本展示了文件上传压测的三大要素:
1. 负载配置(config.phases)
duration: 10min+arrivalRate: 25表示持续 10 分钟、每秒启动 25 个虚拟用户,模拟每分钟 1500 次上传请求的中等压力。arrivalRate是 Artillery 的固定到达率模型,实际请求量还受每个场景内请求数量与思考时间影响。
2. 随机文件轮换(variables)
variables.filename定义了 3 个文件名,Artillery 在每次场景运行时从列表中随机抽取一个值,与模板语法{{ filename }}结合后拼出完整路径./files/artillery-logo.jpg、./files/artillery-installation.pdf、./files/sre-fundamental-rules.png,从而实现"每次上传随机文件"的效果。相比固定上传同一文件,这种随机化更贴近真实用户的上传行为,也避免服务器缓存造成测试失真。若需要按权重分配文件名,可使用weightedPick类权重机制进一步扩展。
3. multipart 表单字段(formData)
document是表单字段名,需与服务器端upload.single('document')严格对应;fromFile指定待上传文件路径。路径是相对于测试脚本所在目录解析的(见下文源码分析),示例中即examples/http-file-uploads/files/;- 路径支持模板表达式,因此可配合变量实现动态选择文件。
运行压测
确保服务器已启动后,在示例目录执行:
artillery run file-uploads.yml运行期间 Artillery 会按phases配置的速率持续向POST /upload发起 multipart 上传请求。仓库集成测试中的 http-file-upload.yml 展示了更完整的用法——同一请求中混合普通文本字段与多个fromFile文件字段:
formData: name: "Artillery" logo: fromFile: "./files/artillery-logo.jpg" guide: fromFile: "./files/{{ filename }}"即formData中既可以有纯文本字段(name),也可以有多个fromFile文件字段,字段名各不相同即可。集成测试还通过afterResponse钩子对上传响应进行断言校验(见 http-file-upload-processor.js),可用于功能验证类场景。
清理上传目录
测试过程中上传的文件会持续写入服务器的uploads/目录,为方便清理,示例提供了:
npm run uploads:clean该命令实际执行del-cli 'uploads/*' '!uploads/.keep'(见 package.json),删除目录内所有上传文件但保留.keep占位文件。也可在服务器代码中接入定期清理策略(如按时间轮转目录),避免压测期间磁盘被写满。
底层实现原理:formData 与 fromFile 是如何工作的
从源码层面深入理解这两个关键字,有助于排查路径、字段、Content-Type 等问题。
HTTP 引擎中的 multipart 处理
文件上传由 HTTP 引擎 engine_http.ts 实现。当检测到params.formData时,引擎按以下流程处理:
- 创建
FormData实例(new FormData())承载 multipart 数据; - 遍历
formData的每个字段,先对值执行模板插值template(v, context); - 若字段值是一个普通对象(
_.isPlainObject):- 存在
contentType时,将其作为该字段的 Content-Type 选项(例如 JSON 字段指定application/json); - 存在
fromFile时,将fromFile路径解析为绝对路径(基于context.vars.$scenarioFile所在目录,即测试脚本所在目录),并用fs.createReadStream(absPath)创建文件读取流作为字段值; - 存在
value时,直接取该值作为普通文本字段内容;
- 存在
- 调用
acc.append(k, V, options)将字段追加到 multipart body,最终作为请求体发送。
相对路径的解析基准
注意fromFile的路径是相对测试脚本文件(.yml)所在目录解析的,而非当前工作目录。示例脚本位于 examples/http-file-uploads/file-uploads.yml,因此./files/{{ filename }}指向examples/http-file-uploads/files/。如果你的测试脚本放在其他目录,务必确认files/的相对位置正确。
Content-Length 与 ENOENT 行为
- 上传的文件流由 Node 的
fs.createReadStream创建,若文件不存在,读取流会触发ENOENT错误——这正是原文档提示"如果文件无法读取,该场景将报告 ENOENT 错误"的原因; - 引擎支持通过
setContentLengthHeader: true显式设置Content-Length头(见 types.d.ts 与 engine_http.ts),对某些严格要求长度头的服务器很有用;设置失败时引擎仅记录 debug 日志,不会中断测试。
类型与 Schema 定义
在 types.d.ts 中,formData被定义为Record<string, unknown>,注释明确其为 "Multipart form (multipart/form-data),e.g. for file uploads";setContentLengthHeader为可选布尔值。配置 schema 侧(engines/http.js)也预留了formData的校验入口。
单元测试佐证
仓库的 HTTP 引擎单元测试 engine_http.test.js 专门覆盖了formDatamultipart 场景,验证了:
- 普通文本字段(
activity、type、location)以Content-Disposition: form-data发送; - 带
contentType: 'application/json'的对象字段会附加对应 Content-Type; - 字段值支持模板变量(
{{ activity }}、{{ climate.temperature }}等)。
这从测试层面印证了formData三种字段形态(纯文本、value+contentType、fromFile文件流)的完整语义。
常见问题与排查思路
| 问题现象 | 可能原因与处理 |
|---|---|
| 场景报 ENOENT | fromFile路径错误或文件不存在;检查路径相对测试脚本所在目录是否正确 |
| 服务器收不到文件 | formData字段名与服务器(如upload.single('document'))不一致 |
| 中文/特殊字符文件名乱码 | 检查服务器端 multipart 解析配置与原文件名编码 |
| 上传文件堆积占满磁盘 | 定期执行npm run uploads:clean,或按轮转策略管理uploads/目录 |
| 需要为文件字段指定 Content-Type | 使用contentType属性(源码见 engine_http.ts) |
小结
通过 http-file-uploads 示例,可以掌握 Artillery 进行文件上传压测的完整链路:Express + Multer 接收服务器搭建、formData+fromFile脚本编写、variables随机文件轮换、模板路径插值,以及setContentLengthHeader等进阶选项。结合 engine_http.ts 的源码实现与单元测试,即可在实际项目中复现并对抗文件上传接口的性能瓶颈。
- 性能测试
- 接口测试
- CLI
【免费下载链接】artillery
The complete load testing platform. Everything you need for production-grade load tests. Serverless & distributed. Load test with Playwright. Load test HTTP APIs, GraphQL, WebSocket, and more. Use any Node.js module.
相关推荐
MWPBench 数学应用题统一评测基准:数据集构成、双引擎评测流程与模糊判分源码解析(unilm/mathscale)
MWPBench 数学应用题统一评测基准:数据集构成、双引擎评测流程与模糊判分源码解析(unilm/mathscale) MWPBench(Math Word
性能测试接口测试CLI使用 React Hook Form 与 FormData 实现 Multipart 文件上传:Refine 实战指南
使用 React Hook Form 与 FormData 实现 Multipart 文件上传:Refine 实战指南 在 React 应用中,向服务器上传图片
前端企业应用Qogir-theme:打造优雅Linux桌面!GTK扁平设计主题完全指南
Qogir theme:打造优雅Linux桌面!GTK扁平设计主题完全指南 Qogir theme是一款专为Linux桌面打造的扁平设计GTK主题,它能瞬间提升
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考