You need to enable JavaScript to run this app.
导航

分片上传(Browser.js SDK)

最近更新时间2024.03.21 15:13:15

首次发布时间2022.07.25 14:32:29

上传大对象时可以分成多个数据块(part)来分别上传,最后调用合并分片将上传的数据块合并为一个对象。

注意事项

  • 为了避免在浏览器环境中暴露您的火山引擎账号密钥信息(即 AccessKey ID 和 AccessKey Secret),强烈建议您使用临时访问凭证的方式执行 TOS 相关操作,详细说明,请参见使用 STS 临时 AK/SK+Token 访问火山引擎 TOS
  • Endpoint 为 TOS 对外服务的访问域名。TOS 支持的 Endpoint 信息,请参见访问域名 Endpoint
  • 分片上传前,您必须具有 tos:PutObject 权限,详细信息,请参见权限配置指南
  • 取消分片上传任务前,您必须具有 tos:AbortMultipartUpload 权限,详细信息,请参见权限配置指南
  • 除了最后一个分片,其他分片大小需要大于等于 4MiB。上传的分片的编号也有范围限制,其范围是 [1, 10000]。
  • 上传对象时,对象名必须满足一定规范,详细信息,请参见对象命名规范
  • TOS 是面向海量存储设计的分布式对象存储产品,内部分区存储了对象索引数据,为横向扩展您上传对象和下载对象时的最大吞吐量,和减小热点分区的概率,请您避免使用字典序递增的对象命名方式,详细信息,请参见性能优化
  • 如果桶中已经存在同名对象,则新对象会覆盖已有的对象。如果您的桶开启了版本控制,则会保留原有对象,并生成一个新版本号用于标识新上传的对象。

分片上传步骤

分片上传包含以下三个步骤:

  1. 初始化分片上传任务
    调用 createMultipartUpload 方法返回 TOS 创建的全局唯一 UploadID。
  2. 上传分片
    调用 uploadPart 方法上传分片数据。

    说明

    • 对于同一个分片上传任务(通过 UploadID 标识),分片编号(PartNumber)标识了该分片在整个对象中的相对位置。若通过同一分片编号上多次上传数据,TOS 中会覆盖原始数据,并以最后一次上传数据为准。
    • 响应头中包含了数据的 MD5 值,可通过 Etag 获取。合并分片时,您需指定当前分片上传任务中的所有分片信息(分片编号、ETag 值)。
  3. 完成分片上传
    所有分片上传完成后,调用 completeMultipartUpload 方法将所有分片合并成一个完整的对象。

示例代码

分片上传完整过程

以下代码展示将本地文件通过分片的方式上传完整过程。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
  </head>

  <body>
    <button id="upload">上传</button>
    <input id="file" type="file" />
    <!-- 导入 SDK 文件 -->
    <script src="https://tos-public.volccdn.com/obj/volc-tos-public/@volcengine/tos-sdk@latest/browser/tos.umd.production.min.js"></script>
    <script type="text/javascript">
      const client = new TOS({
        // yourRegion 填写 Bucket 所在地域。以华北2(北京)为例,yourRegion 填写为 cn-beijing。
        region: yourRegion,
        // 填写 endpoint 名称。
        endpoint: yourEndpoint,
        // 从 STS 服务获取的临时访问密钥(AccessKey ID 和 AccessKey Secret)。
        accessKeyId: yourAccessKey,
        accessKeySecret: yourSecretKey,
        // 从 STS 服务获取的安全令牌(SecurityToken)。
        stsToken: yourSecurityToken,
        // 填写 Bucket 名称。
        bucket: examplebucket,
      });

      // 监听按钮
      const upload = document.getElementById('upload');
      upload.addEventListener('click', async () => {
        const file = document.getElementById('file').files[0];
        const name = 'exampledir/partUploadObject.txt';
        let uploadId = null;
        try {
          const {
            data: { UploadId },
          } = await client.createMultipartUpload({
            key: name,
          });
          uploadId = UploadId;

          // 每个 Part 的大小是 8M
          const PART_SIZE = 8 * 1024 * 1024;
          const uploadPartRes = [];

          // 串行上传每个 Part
          for (let i = 0; i * PART_SIZE < file.size; ++i) {
            const { data } = await client.uploadPart({
              key: name,
              partNumber: i + 1,
              body: file.slice(i * PART_SIZE, Math.min((i + 1) * PART_SIZE, file.size)),
              uploadId: UploadId,
            });
            uploadPartRes[i] = data.ETag;
          }

          await client.completeMultipartUpload({
            key: name,
            parts: uploadPartRes.map((eTag, idx) => ({
              eTag,
              partNumber: idx + 1,
            })),
            uploadId: UploadId,
          });
        } catch (err) {
          console.log(err);
          if (uploadId) {
            // 出错后取消分片
            await client.abortMultipartUpload({
              key: name,
              uploadId,
            });
          }
        }
      });
    </script>
  </body>
</html>

列举已上传分片

以下代码用于列举指定存储桶中指定对象已上传的分片信息。

// 导入 SDK
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
  </head>
  <body>
    <button id="upload">上传</button>
    <input id="file" type="file" />
    <!-- 导入 SDK 文件 -->
    <script src="https://tos-public.volccdn.com/obj/volc-tos-public/@volcengine/tos-sdk@latest/browser/tos.umd.production.min.js"></script>
    <script type="text/javascript">
      const client = new TOS({
        // yourRegion 填写 Bucket 所在地域。以华北2(北京)为例,yourRegion 填写为 cn-beijing。
        region: yourRegion,
        // 填写 endpoint 名称。
        endpoint: yourEndpoint,
        // 从 STS 服务获取的临时访问密钥(AccessKey ID 和 AccessKey Secret)。
        accessKeyId: yourAccessKey,
        accessKeySecret: yourSecretKey,
        // 从 STS 服务获取的安全令牌(SecurityToken)。
        stsToken: yourSecurityToken,
        // 填写 Bucket 名称。
        bucket: examplebucket,
      });

      const bucketName = 'browser-sdk-test-bucket';
      const objectName = 'exampledir/partUploadObject.txt';
      // 分片上传任务 ID,可以从 createMultipartUpload 接口获取
      const uploadId = `65b597dc7eca47bcb99f01647431bd15`;

      // 列举已上传分片
      const {data} = await client.listParts({
        bucket: bucketName,
        key: objectName,
        uploadId,
      });

      console.log('result data:', data);
    </script>
  </body>
</html>

取消分片上传任务

您可以通过 abortMultipartUpload 方法来取消分片上传任务。当一个分片任务被取消后, TOS 会将已上传的分片数据删除,同时您无法再对此分片任务进行任何操作。以下代码用于取消分片上传任务。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
  </head>
  <body>
    <button id="upload">上传</button>
    <input id="file" type="file" />
    <!-- 导入 SDK 文件 -->
    <script src="https://tos-public.volccdn.com/obj/volc-tos-public/@volcengine/tos-sdk@latest/browser/tos.umd.production.min.js"></script>
    <script type="text/javascript">
      const client = new TOS({
        // yourRegion 填写 Bucket 所在地域。以华北2(北京)为例,yourRegion 填写为 cn-beijing。
        region: yourRegion,
        // 填写 endpoint 名称。
        endpoint: yourEndpoint,
        // 从 STS 服务获取的临时访问密钥(AccessKey ID 和 AccessKey Secret)。
        accessKeyId: yourAccessKey,
        accessKeySecret: yourSecretKey,
        // 从 STS 服务获取的安全令牌(SecurityToken)。
        stsToken: yourSecurityToken,
        // 填写 Bucket 名称。
        bucket: examplebucket,
      });

      const bucketName = 'browser-sdk-test-bucket';
      const objectName = 'exampledir/partUploadObject.txt';
      // 分片上传任务 ID,可以从 createMultipartUpload 接口获取
      const uploadId = `65b597dc7eca47bcb99f01647431bd15`;

      // 列举已上传分片
      const {data} = await client.abortMultipartUpload({
        bucket: bucketName,
        key: objectName,
        uploadId,
      });

      console.log('result data:', data);
    </script>
  </body>
</html>