185 lines
4.7 KiB
Markdown
185 lines
4.7 KiB
Markdown
# TAPI 文件上传接入说明
|
||
|
||
本文档说明 `https://tapi.hifast.biz/v1/public/file/upload` 相关上传接口的推荐接入方式、签名规则与常见排查方式。
|
||
|
||
## 总览
|
||
|
||
上传能力包含两类接入方式:
|
||
|
||
- 推荐方式:`init -> S3 PUT -> complete`
|
||
- 兼容方式:`/upload` multipart 直传
|
||
|
||
推荐优先使用预签名三段式,因为:
|
||
|
||
- 现有签名串包含 `BODY_SHA256`
|
||
- `/upload` 是 `multipart/form-data`
|
||
- multipart 原始 body 的签名和调试成本更高
|
||
- `init` 和 `complete` 是 JSON,更适合客户端和 Apifox 调试
|
||
|
||
## 签名生效逻辑
|
||
|
||
项目保持现有旧逻辑,不做强制签名改造:
|
||
|
||
- `Signature.EnableSignature = false` 时:不校验签名
|
||
- `Signature.EnableSignature = true` 且未携带 `X-App-Id` 时:不校验签名,兼容老客户端
|
||
- `Signature.EnableSignature = true` 且携带 `X-App-Id` 时:必须同时携带并校验
|
||
- `X-Timestamp`
|
||
- `X-Nonce`
|
||
- `X-Signature`
|
||
|
||
这意味着:
|
||
|
||
- 新客户端建议始终带完整签名头
|
||
- 老客户端如果没有 `X-App-Id`,仍可按旧逻辑访问
|
||
|
||
## 签名头定义
|
||
|
||
- `X-App-Id`: 客户端标识,例如 `ios-client`
|
||
- `X-Timestamp`: Unix 秒级时间戳
|
||
- `X-Nonce`: 每次请求唯一随机串
|
||
- `X-Signature`: `HMAC-SHA256` 结果的十六进制小写字符串
|
||
|
||
## StringToSign 规则
|
||
|
||
StringToSign 由下面 7 段按换行符 `\n` 拼接:
|
||
|
||
```text
|
||
METHOD
|
||
PATH
|
||
CANONICAL_QUERY
|
||
BODY_SHA256
|
||
X-App-Id
|
||
X-Timestamp
|
||
X-Nonce
|
||
```
|
||
|
||
说明:
|
||
|
||
- `METHOD`:HTTP 方法大写,例如 `POST`
|
||
- `PATH`:请求路径,例如 `/v1/public/file/upload/init`
|
||
- `CANONICAL_QUERY`:按 key 排序后的 query string,没有 query 则为空字符串
|
||
- `BODY_SHA256`:请求体原始字节的 SHA-256 十六进制小写
|
||
- 其余三项直接使用请求头值
|
||
|
||
签名计算方式:
|
||
|
||
```text
|
||
signature = hex_lower(HMAC_SHA256(app_secret, string_to_sign))
|
||
```
|
||
|
||
时间窗与防重放:
|
||
|
||
- `X-Timestamp` 默认有效时间窗是 300 秒
|
||
- `X-Nonce` 在有效时间窗内不能重复使用
|
||
|
||
## 推荐接入:预签名三段式
|
||
|
||
### 1. 初始化上传
|
||
|
||
请求:
|
||
|
||
```bash
|
||
curl -X POST 'https://tapi.hifast.biz/v1/public/file/upload/init' \
|
||
-H 'Accept: application/json, text/plain, */*' \
|
||
-H 'Content-Type: application/json' \
|
||
-H 'authorization: your-token' \
|
||
-H 'X-App-Id: ios-client' \
|
||
-H 'X-Timestamp: 1778776400' \
|
||
-H 'X-Nonce: nonce-001' \
|
||
-H 'X-Signature: your-signature' \
|
||
-d '{
|
||
"biz_type": "app-package",
|
||
"file_name": "demo.zip",
|
||
"content_type": "application/zip",
|
||
"size": 123456,
|
||
"sha256": ""
|
||
}'
|
||
```
|
||
|
||
典型返回:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "success",
|
||
"data": {
|
||
"file_id": "c29274ee26ab5aa211e0396e",
|
||
"object_key": "app-upload/app-package/519/2026/05/c29274ee26ab5aa211e0396e_demo.zip",
|
||
"upload_url": "https://bucket.s3.ap-east-1.amazonaws.com/...",
|
||
"method": "PUT",
|
||
"headers": {
|
||
"Content-Type": "application/zip"
|
||
},
|
||
"expired_at": 1778776715
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2. 直传 S3
|
||
|
||
这一步是直接上传二进制文件到 S3,不走业务签名中间件。
|
||
|
||
```bash
|
||
curl -X PUT 'https://bucket.s3.ap-east-1.amazonaws.com/...' \
|
||
-H 'Content-Type: application/zip' \
|
||
--upload-file '/tmp/demo.zip'
|
||
```
|
||
|
||
说明:
|
||
|
||
- `Content-Type` 需和 `init` 返回的 `headers.Content-Type` 一致
|
||
- `upload_url` 有过期时间,通常 300 秒
|
||
- 成功时 S3 常见返回 `200` 或 `204`
|
||
|
||
### 3. 完成上传
|
||
|
||
```bash
|
||
curl -X POST 'https://tapi.hifast.biz/v1/public/file/upload/complete' \
|
||
-H 'Accept: application/json, text/plain, */*' \
|
||
-H 'Content-Type: application/json' \
|
||
-H 'authorization: your-token' \
|
||
-H 'X-App-Id: ios-client' \
|
||
-H 'X-Timestamp: 1778776405' \
|
||
-H 'X-Nonce: nonce-002' \
|
||
-H 'X-Signature: your-signature' \
|
||
-d '{
|
||
"file_id": "c29274ee26ab5aa211e0396e"
|
||
}'
|
||
```
|
||
|
||
## 兼容接入:单接口 multipart 直传
|
||
|
||
接口:
|
||
|
||
- `POST /v1/public/file/upload`
|
||
|
||
表单字段:
|
||
|
||
- `biz_type`
|
||
- `file`
|
||
|
||
说明:
|
||
|
||
- 该接口继续保留,兼容旧客户端
|
||
- 如果请求带了 `X-App-Id`,就按现有逻辑验签
|
||
- 如果没有 `X-App-Id`,仍按旧逻辑放行
|
||
- 如果要给该接口加签,签名时必须对原始 multipart body 计算 `BODY_SHA256`
|
||
|
||
## 常见错误码
|
||
|
||
- `200`: 成功
|
||
- `400`: 参数错误
|
||
- `40008`: 缺少签名头
|
||
- `40009`: 签名已过期
|
||
- `40010`: 签名无效
|
||
- `40011`: nonce 重放
|
||
- `10001`: 上传元数据不存在或对象不存在
|
||
|
||
## 排查建议
|
||
|
||
- `40008`:确认带了 `X-App-Id` 后,也同时带上 `X-Timestamp / X-Nonce / X-Signature`
|
||
- `40009`:检查客户端时间是否偏差过大
|
||
- `40010`:确认 `PATH`、query 排序、body 原始字节、secret 是否完全一致
|
||
- `40011`:确保每次请求都生成新的 `X-Nonce`
|
||
- `complete` 失败:确认 S3 `PUT` 已成功,且上传大小与 `init.size` 一致
|