docs(spec): 上传 API 增加 fileName + extract=zip 自动解压
- §7.1 补充 fileName (可选)、extract (bool) - 响应统一为 Result<List<SysFileUploadVO>>:单文件也是长度 1 的数组 - §7.4 fileName 行为说明 (不传/传/校验) - §7.5 extract=true (ZIP 解压): - 行为 + 路径规则 (bizType/zipBaseName/entryName) - 安全护栏 (总 entry ≤ 100, 单 entry ≤ maxSize, entry 名正则) - 请求/响应/订阅方事件示例 - 对应后端 commit: c4a5d5f
This commit is contained in:
@@ -275,25 +275,89 @@ Authorization: Bearer <JWT> # 网关已注入,storage 服务再校
|
||||
|
||||
file : MultipartFile (必填)
|
||||
bizType : string (form) (必填;大写蛇形字符串,业务模块自定,框架不维护清单)
|
||||
storage : string (query) (可选,aliyun/tencent/local,不传走 active)
|
||||
storage : string (form) (可选,aliyun/tencent/local,不传走 active)
|
||||
fileName : string (form) (可选;指定存储名,规则 [A-Za-z0-9][A-Za-z0-9._-]{<=200},详见 7.4)
|
||||
extract : bool (form) (可选,默认 false;true 时若文件是 .zip 自动解压为多文件入库,详见 7.5)
|
||||
|
||||
Response (Result<SysFileUploadVO>):
|
||||
Response (Result<List<SysFileUploadVO>>):
|
||||
{
|
||||
"error": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": 1001,
|
||||
"name": "a1b2c3d4.pem",
|
||||
"originalName": "wechat.pem",
|
||||
"url": "https://oss.../cert/2026/06/a1b2c3d4.pem",
|
||||
"size": 2048,
|
||||
"contentType": "application/x-pem-file",
|
||||
"storageType": "ALIYUN",
|
||||
"bizType": "SYS_APP_CERT"
|
||||
}
|
||||
"data": [
|
||||
{
|
||||
"id": 1001,
|
||||
"name": "a1b2c3d4.pem",
|
||||
"originalName": "wechat.pem",
|
||||
"path": "sys-app-cert/2026/06/a1b2c3d4.pem", // 存储路径,不含域名
|
||||
"url": "https://oss.../sys-app-cert/2026/06/a1b2c3d4.pem",
|
||||
"size": 2048,
|
||||
"contentType": "application/x-pem-file",
|
||||
"storageType": "ALIYUN",
|
||||
"bizType": "SYS_APP_CERT"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
> **响应统一是数组**:单文件上传长度为 1,zip 解压上传长度为 N。前端按 `data.length` 即可区分。
|
||||
|
||||
### 7.4 fileName 参数
|
||||
|
||||
| 行为 | 说明 |
|
||||
|------|------|
|
||||
| 不传 | 默认 `bizType/yyyy/MM/{uuid}{ext}`,分布式不冲突 |
|
||||
| 传 | 存储路径为 `bizType/{fileName}`,**会覆盖同名文件**(适用固定路径场景,如 `avatar-{userId}.jpg`)|
|
||||
| 校验 | `^[A-Za-z0-9][A-Za-z0-9._-]{0,199}$`,不合规 400 |
|
||||
|
||||
### 7.5 extract=true(ZIP 自动解压)
|
||||
|
||||
**适用**:批量上传场景(应用多证书、UI 主题包、字体包、翻译文件等)。
|
||||
|
||||
```http
|
||||
POST /storage/upload
|
||||
Content-Type: multipart/form-data
|
||||
|
||||
file : certs.zip (必填,.zip)
|
||||
bizType : SYS_APP_CERT
|
||||
fileName : wechat (可选,作为解压路径的根段)
|
||||
extract : true
|
||||
```
|
||||
|
||||
**行为**:
|
||||
- zip 本身**不**存到后端;解压每个 entry 单独存、单独推 `ON_UPLOAD` 事件
|
||||
- 存储路径:`bizType/{zipBaseName}/{entryName}`,zipBaseName 优先级 `fileName` > 原文件名去 `.zip` > UUID 前 12 位
|
||||
- 响应:`data` 数组长度 = zip 中文件 entry 数(不含目录)
|
||||
- 非 .zip 文件传 `extract=true` → 400
|
||||
|
||||
**安全护栏**(`ZipExtractor` 强制):
|
||||
|
||||
| 项 | 限制 | 失败行为 |
|
||||
|----|------|---------|
|
||||
| 总 entry 数 | ≤ 100 | 400 防 zip bomb / 百万小文件 |
|
||||
| 单 entry 大小 | ≤ `bizType` 配置的 `maxSize` | 400 |
|
||||
| entry 名 | 须匹配 `^[A-Za-z0-9][A-Za-z0-9._-]*(/[A-Za-z0-9][A-Za-z0-9._-]*)*$` | 400(防 Zip Slip / 绝对路径 / Windows 盘符)|
|
||||
| entry 名长度 | ≤ 200 | 400 |
|
||||
|
||||
**典型场景**:
|
||||
```jsonc
|
||||
// 请求
|
||||
file = wechat.zip // 内部: wechat/apiclient_cert.pem, wechat/apiclient_key.pem
|
||||
bizType = "SYS_APP_CERT"
|
||||
fileName = "wechat"
|
||||
extract = true
|
||||
|
||||
// 响应
|
||||
{
|
||||
"error": 0,
|
||||
"data": [
|
||||
{ "id": 1001, "name": "wechat/apiclient_cert.pem", "path": "sys-app-cert/wechat/apiclient_cert.pem", ... },
|
||||
{ "id": 1002, "name": "wechat/apiclient_key.pem", "path": "sys-app-cert/wechat/apiclient_key.pem", ... }
|
||||
]
|
||||
}
|
||||
|
||||
// 订阅方收到 2 条 ON_UPLOAD,type 都是 "SYS_APP_CERT_UPLOAD",bizType=SYS_APP_CERT
|
||||
```
|
||||
|
||||
### 7.2 查询文件
|
||||
|
||||
```http
|
||||
|
||||
Reference in New Issue
Block a user