Skip to content

初始化分片上传

1. 接口定位

  • 接口名称: 初始化分片上传
  • 所属域: object
  • 业务目标: 发起大文件的分片上传会话;若服务端已存在相同 hash 的文件,则直接返回访问 URL(秒传),否则返回分片上传所需的签名信息

2. 请求定义

  • Method: POST
  • Path: /object/initiate_multipart_upload
  • Content-Type: 推荐 application/json
  • operationID: 必填,请通过 Header operationID 传入
  • 鉴权: 必填,需要通过 Header token 传入有效令牌
  • 幂等性: 非幂等(会话状态与签名 URL 有时效性)

3. 请求参数

Header 参数

字段必填类型说明
operationIDstring链路追踪 ID
tokenstring登录令牌

Body 参数

字段必填类型说明
hashstring文件内容的 MD5 哈希(hex 编码),用于秒传判断和完整性校验
sizeint64文件总大小(字节)
maxPartsint32期望的最大分片数,服务端会据此计算建议分片大小
namestring目标对象存储路径(含文件名),如 user/avatar/xxx.jpg
contentTypestring文件 MIME 类型,如 image/jpeg
causestring上传来源标记,用于文件分组管理
urlPrefixstring返回 URL 的前缀(scheme+host),不传则使用服务端默认配置

4. 响应结构

通用响应包裹

字段类型说明
errCodeint错误码,0 表示成功
errMsgstring错误简述
errDltstring错误详情
dataany业务数据

两种响应路径

服务端会对 hash 做已存在判断,返回结构因此有两种情况:

路径一:秒传(文件已存在)

data.uploadnulldata.url 不为空,调用方可直接使用该 URL,无需继续上传。

字段类型说明
urlstring文件访问 URL
uploadnull秒传时不返回上传信息

路径二:需要分片上传

data.upload 不为 null,调用方需按签名信息完成各分片上传后调用 complete_multipart_upload 提交。

字段类型说明
urlstring上传完成后可使用的预期 URL(完成前无效)
uploadobject分片上传会话信息

upload 字段结构

字段类型说明
uploadIDstring分片上传会话 ID,complete_multipart_upload 时需要
partSizeint64每个分片的大小(字节),客户端按此分割文件
signobject分片上传签名信息(部分存储后端可能为 null
expireTimeint64签名过期时间(毫秒时间戳),超时后需重新发起

sign 字段结构

字段类型说明
urlstring基础上传 URL
queryarray[object]公共 query 参数,每个元素含 key(string)和 values(array[string])
headerarray[object]公共请求头参数
partsarray[object]各分片的独立签名,见下表

parts 元素(SignPart)

字段类型说明
partNumberint32分片序号(从 1 开始)
urlstring该分片的上传 URL
queryarray[object]该分片的 query 参数
headerarray[object]该分片的请求头参数

5. 业务规则

  • 调用方持有合法 token 即可调用,无角色限制。
  • 服务端对请求的 name 做命名规则校验,非法文件名会返回参数错误。
  • 上传签名有有效期(expireTime),过期后需重新调用本接口获取新签名。
  • 分片上传流程:initiate_multipart_upload → 按 parts 中的签名逐片 PUT → complete_multipart_upload
  • 若请求时文件 hash 已存在,服务端直接入库并返回 URL,跳过上传流程(秒传)。

6. 错误码与失败场景

错误码场景典型报错
1001参数不合法(hash 为空、文件名非法等)ArgsError
500服务内部错误(对象存储调用失败等)ServerInternalError

7. 示例

fetch 请求示例

javascript
fetch("http://localhost:10002/object/initiate_multipart_upload", {
  method: "POST",
  headers: {
    operationID: "c57f1e82-0d3b-4ade-a5f5-e9f3b2d94f03",
    token: "<your-token>",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    hash: "d41d8cd98f00b204e9800998ecf8427e",
    size: 52428800,
    maxParts: 10,
    name: "user/file/20260620/example.mp4",
    contentType: "video/mp4",
    cause: "chat_attachment",
  }),
})
  .then((res) => res.json())
  .then((data) => console.log(data));

请求示例(JSON)

json
{
  "hash": "d41d8cd98f00b204e9800998ecf8427e",
  "size": 52428800,
  "maxParts": 10,
  "name": "user/file/20260620/example.mp4",
  "contentType": "video/mp4",
  "cause": "chat_attachment"
}

成功响应示例(需上传)

json
{
  "errCode": 0,
  "errMsg": "",
  "errDlt": "",
  "data": {
    "url": "https://minio.example.com/openim/user/file/20260620/example.mp4",
    "upload": {
      "uploadID": "3a7b5c-upload-session-id",
      "partSize": 5242880,
      "expireTime": 1750501200000,
      "sign": {
        "url": "https://minio.example.com/openim",
        "query": [],
        "header": [],
        "parts": [
          {
            "partNumber": 1,
            "url": "https://minio.example.com/openim/part1",
            "query": [{ "key": "partNumber", "values": ["1"] }],
            "header": []
          }
        ]
      }
    }
  }
}

成功响应示例(秒传)

json
{
  "errCode": 0,
  "errMsg": "",
  "errDlt": "",
  "data": {
    "url": "https://minio.example.com/openim/user/file/20260620/example.mp4",
    "upload": null
  }
}

8. 时序流程

完整分片上传流程:

  1. 调用 initiate_multipart_upload,获取 uploadID 和各分片签名。
  2. 客户端按 partSize 分割文件,对每个分片调用 parts[i].url(PUT 请求,附带对应 query/header)。
  3. 所有分片上传完成后,调用 complete_multipart_upload 提交,获取最终 URL。

秒传场景:

  1. 调用 initiate_multipart_upload,若 hash 命中服务端缓存,直接返回 urluploadnull
  2. 调用方直接使用返回的 URL,不需要上传。

9. 变更记录

  • 2026-06-20: 首版补充文档发布。