# 预签名直传 服务端预生成上传地址,客户端直接向存储引擎(或服务端代理)上传文件,最后确认建分享。 两种模式: | 模式 | 引擎 | 上传方式 | |---|---|---| | `direct` | S3(含 MinIO/R2 等 S3 兼容存储) | 客户端 `PUT` 到预签名 URL,直连对象存储 | | `proxy` | 本地 / WebDAV | 客户端 `PUT` multipart 到服务端代理接口 | > 本地 / WebDAV 引擎不支持预签名直链,init 返回正常 `proxy` 模式(仅当引擎预签名调用本身异常时才报错)。 > 会话有效期 **900 秒**(15 分钟)。proxy 模式响应另含 `legacy_proxy_upload_url` > (`/api` 前缀的兼容别名,已废弃,与 `upload_url` 等价)。 > 全部端点经审计中间件落库(action=upload)。 ## 上传流程 ```text direct 模式: POST /presign/upload/init → upload_url(S3 预签名 PUT) PUT → 客户端直传 S3(无认证头) POST /presign/upload/confirm/{id} → 确认 → 取件码 proxy 模式: POST /presign/upload/init → upload_url = /presign/upload/proxy/{id} PUT /presign/upload/proxy/{id} → multipart 上传,服务端转存并直接建分享 ``` ## 初始化:POST /presign/upload/init **请求体**(JSON,亦兼容表单): | 参数 | 类型 | 必需 | 默认 | 说明 | |---|---|---|---|---| | `file_name` | string | ✅ | - | 文件名(清理 + 白名单校验) | | `file_size` | int | ✅ | - | 文件字节数(≤ 生效上限:`max_file_size>0` 时为其,否则 `uploadSize`) | | `expire_value` | int | ❌ | `1` | 过期值(`count` 型受 `max_save_count` 约束) | | `expire_style` | string | ❌ | `day` | 过期方式(须在 `expireStyle` 白名单内) | **curl 示例**: ```bash curl -s -X POST http://localhost:8466/presign/upload/init \ -H 'Content-Type: application/json' \ -d '{"file_name":"backup.zip","file_size":20971520,"expire_value":7,"expire_style":"day"}' ``` **S3(direct)成功响应**(200): ```json { "code": 200, "msg": "ok", "data": { "upload_id": "6a1e…", "upload_url": "https://minio:9000/filecodebox/share/data/2025/06/01/6a1e…/backup.zip?X-Amz-…", "mode": "direct", "expires_in": 900, "file_path": "share/data/2025/06/01/6a1e…" } } ``` **local/WebDAV(proxy)成功响应**(200): ```json { "code": 200, "msg": "ok", "data": { "upload_id": "6a1e…", "upload_url": "/presign/upload/proxy/6a1e…", "proxy_upload_url": "/presign/upload/proxy/6a1e…", "mode": "proxy", "expires_in": 900, "file_path": "share/data/2025/06/01/6a1e…" } } ``` **错误响应**: ```json { "code": 403, "msg": "大小超过限制,最大为10.00 MB" } ``` > 大小上限为动态策略(v2 需求 ④⑩):管理端改 `max_file_size`(0=回落 `uploadSize`)后 > 立即按新上限校验 init 声明的 `file_size`。 ```json { "code": 403, "msg": "不允许上传该类型文件" } ``` ```json { "code": 507, "msg": "存储空间已达到管理员设置的容量上限" } ``` ## 直传确认:POST /presign/upload/confirm/{uploadID} `direct` 模式专用:客户端向 S3 `PUT` 完成后调用。服务端会核对实际对象(多引擎一致): - **大小核对**:实际大小与声明差 >1KB → 400「文件大小与声明不符」;超过策略上限(`max_file_size`)→ **删除对象、释放容量预留**并 403; - **内容校验**:取对象前 64 字节做 magic bytes 白名单校验(失败删除对象并报错); - 全部通过后创建分享记录。 ```bash # 1) 直传 S3(注意:不要带 Authorization 头,预签名 URL 自带鉴权) curl -X PUT "" --upload-file ./backup.zip # 2) 确认 curl -s -X POST http://localhost:8466/presign/upload/confirm/6a1e… ``` **成功响应**(200): ```json { "code": 200, "msg": "ok", "data": { "code": "B4N8Q", "name": "backup.zip" } } ``` **错误响应**: ```json { "code": 404, "msg": "文件未上传或上传失败" } ``` ```json { "code": 400, "msg": "文件大小与声明不符" } ``` ```json { "code": 403, "msg": "文件大小超过限制" } ``` ```json { "code": 400, "msg": "此会话不支持direct模式" } ``` ## 代理上传:PUT /presign/upload/proxy/{uploadID} `proxy` 模式专用:multipart 上传到服务端,服务端流式转存到存储引擎后立即创建分享记录。 **multipart 字段**:`file`(必需)。 **curl 示例**: ```bash curl -s -X PUT http://localhost:8466/presign/upload/proxy/6a1e… -F 'file=@./backup.zip' ``` **成功响应**(200): ```json { "code": 200, "msg": "ok", "data": { "code": "B4N8Q", "name": "backup.zip" } } ``` **错误响应**: ```json { "code": 400, "msg": "缺少上传文件 file 字段" } ``` ```json { "code": 400, "msg": "文件大小与声明不符" } ``` ```json { "code": 403, "msg": "大小超过限制,最大为10.00 MB" } ``` > 文件实际大小须与 init 声明的 `file_size` 一致(±1KB 容差);成功后会话即删除,不可重复使用。 ## 查询会话:GET /presign/upload/status/{uploadID} ```bash curl -s http://localhost:8466/presign/upload/status/6a1e… ``` **成功响应**(200): ```json { "code": 200, "msg": "ok", "data": { "upload_id": "6a1e…", "file_name": "backup.zip", "file_size": 20971520, "mode": "proxy", "created_at": "2025-06-01T12:00:00+08:00", "expires_at": "2025-06-01T12:15:00+08:00", "is_expired": false } } ``` ## 取消会话:DELETE /presign/upload/{uploadID} 删除会话并释放容量预留;`direct` 模式会尽力清理已直传到 S3 的对象。 ```bash curl -s -X DELETE http://localhost:8466/presign/upload/6a1e… ``` ```json { "code": 200, "msg": "ok", "data": { "message": "上传会话已取消" } } ``` ```json { "code": 404, "msg": "上传会话不存在" } ``` ```json { "code": 404, "msg": "上传会话已过期" } ```