f452f80100
- 在 etc/ppanel.yaml 与 internal/config/config.go 的 S3.AllowedContentTypes 新增 image/jpeg,image/jpg,image/png,image/webp,image/gif,image/heic,image/heif,image/bmp - 保留原 zip/gzip/text/json/octet-stream - validateInitRequest 在拒绝时携带 content_type is not allowed 业务消息 - 新增 internal/logic/public/file/common_test.go,覆盖允许/拒绝及无 Content-Type 嗅探 - doc/tapi-file-upload-zh.md 同步允许类型列表与错误码说明 Co-authored-by: multica-agent <github@multica.ai>
5.4 KiB
5.4 KiB
TAPI 文件上传接入说明
本文档说明 https://tapi.hifast.biz/v1/public/file/upload 相关上传接口的推荐接入方式、签名规则与常见排查方式。
总览
上传能力包含两类接入方式:
- 推荐方式:
init -> S3 PUT -> complete - 兼容方式:
/uploadmultipart 直传
推荐优先使用预签名三段式,因为:
- 现有签名串包含
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-TimestampX-NonceX-Signature
这意味着:
- 新客户端建议始终带完整签名头
- 老客户端如果没有
X-App-Id,仍可按旧逻辑访问
签名头定义
X-App-Id: 客户端标识,例如ios-clientX-Timestamp: Unix 秒级时间戳X-Nonce: 每次请求唯一随机串X-Signature:HMAC-SHA256结果的十六进制小写字符串
StringToSign 规则
StringToSign 由下面 7 段按换行符 \n 拼接:
METHOD
PATH
CANONICAL_QUERY
BODY_SHA256
X-App-Id
X-Timestamp
X-Nonce
说明:
METHOD:HTTP 方法大写,例如POSTPATH:请求路径,例如/v1/public/file/upload/initCANONICAL_QUERY:按 key 排序后的 query string,没有 query 则为空字符串BODY_SHA256:请求体原始字节的 SHA-256 十六进制小写- 其余三项直接使用请求头值
签名计算方式:
signature = hex_lower(HMAC_SHA256(app_secret, string_to_sign))
时间窗与防重放:
X-Timestamp默认有效时间窗是 300 秒X-Nonce在有效时间窗内不能重复使用
推荐接入:预签名三段式
1. 初始化上传
请求:
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": ""
}'
典型返回:
{
"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,不走业务签名中间件。
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一致- 允许的
Content-Type由服务端S3.AllowedContentTypes配置控制,默认包含:- 压缩包:
application/zip、application/x-zip-compressed、application/gzip、application/x-gzip - 通用文件:
application/octet-stream、text/plain、application/json - 图片:
image/jpeg、image/jpg、image/png、image/webp、image/gif、image/heic、image/heif、image/bmp
- 压缩包:
upload_url有过期时间,通常 300 秒- 成功时 S3 常见返回
200或204
3. 完成上传
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_typefile
说明:
- 该接口继续保留,兼容旧客户端
- 如果请求带了
X-App-Id,就按现有逻辑验签 - 如果没有
X-App-Id,仍按旧逻辑放行 - 如果要给该接口加签,签名时必须对原始 multipart body 计算
BODY_SHA256 - 允许的
Content-Type与预签名三段式一致;multipart 文件字段未显式携带Content-Type时,服务端会基于文件内容嗅探常见类型。
常见错误码
200: 成功400: 参数错误400 content_type is not allowed: 文件Content-Type不在S3.AllowedContentTypes白名单内40008: 缺少签名头40009: 签名已过期40010: 签名无效40011: nonce 重放10001: 上传元数据不存在或对象不存在
排查建议
40008:确认带了X-App-Id后,也同时带上X-Timestamp / X-Nonce / X-Signature40009:检查客户端时间是否偏差过大40010:确认PATH、query 排序、body 原始字节、secret 是否完全一致40011:确保每次请求都生成新的X-Noncecomplete失败:确认 S3PUT已成功,且上传大小与init.size一致