构造 ApacheBench 可用的 postfile

原文地址:https://wyiyi.github.io/amber/2024/08/01/ApacheBench/


description: "本文描述了如何使用 ApacheBench 测试文件上传接口"
date: 2024.08.04 10:34
categories:
- Test
tags: [HTTP, Java]
keywords: Apache Bench, ab, test, postfile, putfile, media-type, multipart/form-data, RFC 7578, RFC 2046, CRLF, boundary, Content-Disposition, form-data, filename


摘要

Web 开发过程中,文件上传功能是常见的需求。对于开发者而言,确保上传功能的稳定性和性能至关重要。

本文将带你了解如何使用ApacheBench性能测试工具对文件上传功能进行性能测试,特别是如何按照规范构造上传文件的请求体,以便评估和提高服务器在高并发情况下的处理能力。

ApacheBench 简介

ApacheBench(简称ab)是 Apache 服务器自带的一个性能测试工具,它能够模拟多用户并发请求,从而评估服务器在高负载下的性能表现。若系统中未安装 Apache 服务器,可前往 Apache 官网下载和安装。更多关于 ApacheBench 的信息,请参考:ApacheBench 简介

前置条件

假设有一个文件上传 POST 接口 http://localhost:8080/upload ,在请求体中接受 keyfile 的文件,并返回上传的文件名和文件大小:

postfile-for-ab.png

通过 Postman 等工具,我们可以直观地看到上传文件的请求内容:

POST /upload HTTP/1.1
Host: localhost:8080
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Length: 204

------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file"; filename="/C:/Users/admin/Desktop/test.jpg"
Content-Type: image/jpeg

(data)
------WebKitFormBoundary7MA4YWxkTrZu0gW--

问题

当需要使用 ApacheBench 测试上传文件的 POST 接口时,ab -h 中只写到了通过 -p 参数指定 postfile

-p postfile File containing data to POST. Remember also to set -T

那么这个 postfile 中包含哪些内容呢?应该如何构造一个 ApacheBench 可用的 postfile 呢?

有关 multipart/form-data 的规范

RFC 7578 第4节 中关于 multipart/form-data 的定义提到:multipart/form-data 遵循 RFC 2046 第 5.1 节 中定义的多部分 MIME 数据流结构,并有一些变化,大致的结构要求如下:

  1. 请求头必须包含 Content-Type: multipart/form-data; boundary=边界分隔符
  2. 多部分文件需要组合成一个单个的请求体,边界分隔符 字符串需保证在整个请求体内唯一,不会出现在分割行以外的其他部分;
  3. 请求体必须包含一个或多个部分,每部分一个实体(如:文件);
  4. 各部分使用 CRLF +-- +边界分隔符作为一个边界分割行进行分隔,最后一部分后面使用 边界分隔行 +--表示结束;换行符均需使用 CRLF(即 \r\n,即使在非 Windows 环境中);
  5. 每部分在边界分隔行之间,又由三部分组成:头区域、空白行、内容区域;
  6. 每部分头区域必须包含 Content-Disposition 头字段,类型为 form-data;同时必须包含 name 参数,值为 form 中的原始字段名;当内容区域表示的是文件时,还应该提供 filename 参数。

更详细的内容可参考上面引用的 RFC 规范文档。

构造 postfile

下面依照规范中格式要求,构造一个只发送一个文件的 postfile

1. 准备 postfile 文件

  • 准备要上传的文件:如:test.jpg
  • 新建一个文本文件,命名为postfile.txt

2. 确定边界分隔符

选择一个不会在文件内容中出现的字符串作为边界分隔符,例如:----WebKitFormBoundary7MA4YWxkTrZu0gW

3. 编写 postfile 头区域及空白行

postfile.txt 中写入以下内容,这些内容构成了请求体的头部信息,其中 name 应该与服务器端接收的字段名一致,filename 是要上传的文件的名称。

------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file"; filename="test.jpg"
Content-Type: image/jpeg

依据规范描述,Content-Type 头字段非必要。

此处需注意:

因为规范要求使用CRLF作为换行符,在非 Windows 环境中,不能直接使用文本编辑器输入上面内容,可以按如下方式通过命令构造此部分内容:

$ echo -e '------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name="file"; filename="test.jpg"\r\nContent-Type: image/jpeg\r\n\r' > postfile.txt

通过 >>>向文件中添加内容时,会自动在最后追加一个 LR(\n),所以省略最后一个 \n

使用 cat -e 可验证换行符,每行结尾是 ^M$ 代表 CRLF换行符:

$ cat -e postfile.txt
------WebKitFormBoundary7MA4YWxkTrZu0gW^M$
Content-Disposition: form-data; name="file"; filename="test.jpg"^M$
Content-Type: image/jpeg^M$
^M$

4. 添加文件内容至 postfile 内容区域

由于文件内容通常是二进制数据,不能直接在文本编辑器中粘贴,可使用 cat 命令将文件内容追加至 postfile 中:

# 将 test.jpg 文件内容追加到 postfile.txt
$ cat test.jpg >> postfile.txt

Windows 系统中可在 git bash 中使用 cat 命令。

5. 添加结束标记

最后以 CRLF+-- +边界分隔符+-- 标记结束:

# 将结束标记添加到 postfile.txt
$ echo -e "\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--" >> postfile.txt

因为在将文件流内容追加至 postfile.txt 文件后,已无法使用文本编辑器直接打开此文件,故继续使用命令追加文件内容,同样在 Windows 环境中可以通过 git bash 使用 echo 命令。

执行 ab 命令

使用以下命令执行文件上传测试:

$ ab -n 1 -c 1 -p postfile.txt -v 2 \
-T "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW" \
http://localhost:8080/upload \
-v 2
  • -n 1 表示总共发送 1 个请求(根据实际测试需求进行调整)。
  • -c 1 表示同时并发 1 个请求(根据实际测试需求进行调整)。
  • -p postfile.txt 指定包含POST数据的文件。
  • -T "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW" 指定请求的内容类型,包括之前定义的边界分隔符。
  • -v verbosity用于设置 ApacheBench 的详细输出级别。在详细输出级别 2 下,ApacheBench会打印出警告信息和信息信息,如:请求和响应的头部信息。

执行命令后,在控制台中,可以在 LOG: header received: 消息之后找到响应状态码和响应内容。如果状态码为 200且和预期值一致,表示服务器成功处理了请求。

在控制台中还会提供一系列关键指标,如每秒请求数、请求平均响应时间等关键指标。这些数据可以帮助分析文件上传的性能表现,并为优化提供依据。

This is ApacheBench, Version 2.3 <$Revision: 1901567 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)...INFO: POST header ==
---
POST /upload HTTP/1.0
Content-length: 24223
Content-type: multipart/form-data; boundary=---WebKitFormBoundary7MA4YWxkTrZu0gW
secret-id: 3e6bec50-3bbd-4443-b141-82aaee645cc7
secret-key: f1596671ce4d30a7847a91b8c674f43c
Host: localhost:8080
User-Agent: ApacheBench/2.3
Accept: */*


---
LOG: header received:
HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 113
Date: Wed, 31 Jul 2024 13:37:18 GMT
Connection: close

File uploaded successfully: postfile.txt with size: 24072 bytes
..done


Server Software:
Server Hostname:        localhost
Server Port:            8080

Document Path:          /upload
Document Length:        113 bytes

Concurrency Level:      1
Time taken for tests:   0.056 seconds
Complete requests:      1
Failed requests:        0
Total transferred:      247 bytes
Total body sent:        24512
HTML transferred:       113 bytes
Requests per second:    17.73 [#/sec] (mean)
Time per request:       56.388 [ms] (mean)
Time per request:       56.388 [ms] (mean, across all concurrent requests)
Transfer rate:          4.28 [Kbytes/sec] received
                        424.51 kb/s sent
                        428.79 kb/s total

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       0
Processing:    56   56   0.0     56      56
Waiting:       53   53   0.0     53      53
Total:         56   56   0.0     56      56

扩展 putfile

ApacheBench (ab) 同样适用于测试 PUT接口。构造putfile的方法与POST接口类似,只需确保请求体的内容和头部信息符合PUT请求的要求。

-u putfile File containing data to PUT. Remember also to set -T

附录

单个文件

构造命令:

echo -e '------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name="file"; filename="file1.jpg"\r\n\r' > postfile.txt
cat 1.jpg >> postfile.txt
echo -e "\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--" >> postfile.txt

发送请求:

ab -n 1 -c 1 -p postfile.txt -v 2 \
-T "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW" \
http://localhost:8080/upload

多个文件

构造命令:

echo -e '------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name="file1"; filename="file1.jpg"\r\n\r' > postfile.txt
cat 1.jpg >> postfile.txt
echo -e "\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r" >> postfile.txt
echo -e 'Content-Disposition: form-data; name="file2"; filename="file2.zip"\r\n\r' >> postfile.txt
cat demo.zip >> postfile.txt
echo -e "\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--" >> postfile.txt

发送请求:

ab -n 1 -c 1 -p postfile.txt -v 2 \
-T "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW" \
http://localhost:8080/upload2
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容