docs: 更新 OpenAPI 文档,新增批量下载 URL 接口文档
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m15s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m15s
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -4268,6 +4268,30 @@ components:
|
|||||||
description: 总订单数
|
description: 总订单数
|
||||||
type: integer
|
type: integer
|
||||||
type: object
|
type: object
|
||||||
|
DtoGetBatchDownloadURLsRequest:
|
||||||
|
properties:
|
||||||
|
file_keys:
|
||||||
|
description: 文件路径标识列表,最多 50 个
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
minLength: 1
|
||||||
|
nullable: true
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- file_keys
|
||||||
|
type: object
|
||||||
|
DtoGetBatchDownloadURLsResponse:
|
||||||
|
properties:
|
||||||
|
expires_in:
|
||||||
|
description: URL 有效期(秒)
|
||||||
|
type: integer
|
||||||
|
urls:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: file_key 到预签名下载 URL 的映射
|
||||||
|
nullable: true
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
DtoGetUploadURLRequest:
|
DtoGetUploadURLRequest:
|
||||||
properties:
|
properties:
|
||||||
content_type:
|
content_type:
|
||||||
@@ -21150,6 +21174,142 @@ paths:
|
|||||||
summary: 代理商资金概况
|
summary: 代理商资金概况
|
||||||
tags:
|
tags:
|
||||||
- 代理商资金管理
|
- 代理商资金管理
|
||||||
|
/api/admin/storage/batch-download-urls:
|
||||||
|
post:
|
||||||
|
description: |-
|
||||||
|
## 文件展示流程
|
||||||
|
|
||||||
|
本接口用于批量获取对象存储文件的预签名下载 URL。由于存储桶为私有访问,文件不能直接通过路径访问,必须通过预签名 URL 才能展示。
|
||||||
|
|
||||||
|
### 为什么需要这个接口
|
||||||
|
|
||||||
|
对象存储使用私有 Bucket,文件路径(file_key)本身无法直接访问。前端持有的 file_key 只是文件标识,需要通过本接口换取带签名的临时访问 URL,才能在 `<img>` 或下载链接中使用。
|
||||||
|
|
||||||
|
### 完整使用流程
|
||||||
|
|
||||||
|
1. **业务接口返回 file_key**(存储在数据库中的文件路径标识)
|
||||||
|
2. **调用本接口** 传入所有需要展示的 file_key 列表
|
||||||
|
3. **使用返回的 URL** 直接赋值给 `<img src>` 或下载链接,图片/文件内容直接从对象存储加载,不经过后端
|
||||||
|
|
||||||
|
### 列表页批量展示示例
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 假设列表数据中每条记录有 avatar_key 字段
|
||||||
|
const listData = await api.get('/customers');
|
||||||
|
|
||||||
|
// 收集所有 file_key(过滤掉空值)
|
||||||
|
const fileKeys = listData.map(item => item.avatar_key).filter(Boolean);
|
||||||
|
|
||||||
|
// 一次性换取所有下载 URL
|
||||||
|
const { data } = await api.post('/storage/batch-download-urls', {
|
||||||
|
file_keys: fileKeys
|
||||||
|
});
|
||||||
|
|
||||||
|
// 渲染时通过 map 取对应 URL
|
||||||
|
listData.forEach(item => {
|
||||||
|
item.avatarUrl = data.urls[item.avatar_key] ?? '';
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 单个文件展示示例
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 详情页只有一个文件时,也走批量接口(保持一致)
|
||||||
|
const { data } = await api.post('/storage/batch-download-urls', {
|
||||||
|
file_keys: [record.license_key]
|
||||||
|
});
|
||||||
|
|
||||||
|
const licenseUrl = data.urls[record.license_key];
|
||||||
|
```
|
||||||
|
|
||||||
|
### 前端缓存建议
|
||||||
|
|
||||||
|
预签名 URL 有效期 **24 小时**,建议在内存中缓存,避免同一页面重复请求:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const urlCache = new Map(); // key: file_key, value: { url, expireAt }
|
||||||
|
|
||||||
|
async function getFileUrl(fileKey) {
|
||||||
|
const cached = urlCache.get(fileKey);
|
||||||
|
if (cached && cached.expireAt > Date.now()) {
|
||||||
|
return cached.url;
|
||||||
|
}
|
||||||
|
const { data } = await api.post('/storage/batch-download-urls', {
|
||||||
|
file_keys: [fileKey]
|
||||||
|
});
|
||||||
|
const url = data.urls[fileKey];
|
||||||
|
urlCache.set(fileKey, { url, expireAt: Date.now() + data.expires_in * 1000 * 0.9 });
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 注意事项
|
||||||
|
|
||||||
|
- 单次请求最多 **50 个** file_key
|
||||||
|
- 预签名 URL 有效期 **24 小时**,过期后需重新获取
|
||||||
|
- file_key 不存在时对应的 URL 生成会失败,整个请求返回错误
|
||||||
|
- 图片/文件内容直接从对象存储加载到浏览器,**不经过后端**,不消耗服务器带宽
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/DtoGetBatchDownloadURLsRequest'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
properties:
|
||||||
|
code:
|
||||||
|
description: 响应码
|
||||||
|
example: 0
|
||||||
|
type: integer
|
||||||
|
data:
|
||||||
|
$ref: '#/components/schemas/DtoGetBatchDownloadURLsResponse'
|
||||||
|
msg:
|
||||||
|
description: 响应消息
|
||||||
|
example: success
|
||||||
|
type: string
|
||||||
|
timestamp:
|
||||||
|
description: 时间戳
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- code
|
||||||
|
- msg
|
||||||
|
- data
|
||||||
|
- timestamp
|
||||||
|
type: object
|
||||||
|
description: 成功
|
||||||
|
"400":
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/ErrorResponse'
|
||||||
|
description: 请求参数错误
|
||||||
|
"401":
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/ErrorResponse'
|
||||||
|
description: 未认证或认证已过期
|
||||||
|
"403":
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/ErrorResponse'
|
||||||
|
description: 无权访问
|
||||||
|
"500":
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/ErrorResponse'
|
||||||
|
description: 服务器内部错误
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
|
summary: 批量获取文件下载预签名 URL
|
||||||
|
tags:
|
||||||
|
- 对象存储
|
||||||
/api/admin/storage/upload-url:
|
/api/admin/storage/upload-url:
|
||||||
post:
|
post:
|
||||||
description: |-
|
description: |-
|
||||||
|
|||||||
Reference in New Issue
Block a user