使用断点续传上传的方式将文件上传到 TOS 时,您可以设置分片大小、上传分片的并发数、上传时客户端限速、事件回调函数等。上传过程中,如果出现网络异常或程序崩溃导致文件上传失败时,将从断点记录处继续上传未上传完成的部分。在上传的过程中可以通过调用传入的 cancelToken 中的 Cancel 方法取消对象上传。
tos:PutObject
权限,具体操作,请参见权限配置指南。Checkpoint
文件中,所以程序需要对 Checkpoint
文件有写权限。Checkpoint
文件中,如果上传过程中某一分片上传失败,再次上传时会 Checkpoint
文件中记录的点继续上传。上传完成后, Checkpoint
文件会被删除。以下代码用于断点续传的方式上传文件。
// 导入 SDK, 当 TOS Node.JS SDK 版本小于 2.5.2 请把下方 TosClient 改成 TOS 导入 import { TosClient, TosClientError, TosServerError } from '@volcengine/tos-sdk'; // 创建客户端 const client = new TosClient({ accessKeyId: process.env['TOS_ACCESS_KEY'], accessKeySecret: process.env['TOS_SECRET_KEY'], region: "Provide your region", // 填写 Bucket 所在地域。以华北2(北京)为例,则 "Provide your region" 填写为 cn-beijing。 endpoint: "Provide your endpoint", // 填写域名地址 }); function handleError(error) { if (error instanceof TosClientError) { console.log('Client Err Msg:', error.message); console.log('Client Err Stack:', error.stack); } else if (error instanceof TosServerError) { console.log('Request ID:', error.requestId); console.log('Response Status Code:', error.statusCode); console.log('Response Header:', error.headers); console.log('Response Err Code:', error.code); console.log('Response Err Msg:', error.message); } else { console.log('unexpected exception, message: ', error); } } async function main() { try { const bucketName = 'node-sdk-test-bucket'; const objectName = 'example_dir/multipartExample'; // 本地 example_dir 文件夹下的 multipartExample 文件 const filePath = './example_dir/multipartExample'; const { data } = await client.uploadFile({ bucket: bucketName, key: objectName, // 上传的文件路径 file: filePath, // 上传时指定分片大小 partSize: 5 * 1024 * 1024, // 分片上传任务并发数量 taskNum: 5, }); console.log('uploadFile result', data); } catch (error) { handleError(error); } } main();
// 导入 SDK, 当 TOS Node.JS SDK 版本小于 2.5.2 请把下方 TosClient 改成 TOS 导入 import { TosClient, TosClientError, TosServerError } from '@volcengine/tos-sdk'; import fsp from 'fs/promises'; import path from 'path'; // 创建客户端 const client = new TosClient({ accessKeyId: process.env['TOS_ACCESS_KEY'], accessKeySecret: process.env['TOS_SECRET_KEY'], region: "Provide your region", // 填写 Bucket 所在地域。以华北2(北京)为例,则 "Provide your region" 填写为 cn-beijing。 endpoint: "Provide your endpoint", // 填写域名地址 }); function handleError(error) { if (error instanceof TosClientError) { console.log('Client Err Msg:', error.message); console.log('Client Err Stack:', error.stack); } else if (error instanceof TosServerError) { console.log('Request ID:', error.requestId); console.log('Response Status Code:', error.statusCode); console.log('Response Header:', error.headers); console.log('Response Err Code:', error.code); console.log('Response Err Msg:', error.message); } else { console.log('unexpected exception, message: ', error); } } async function main() { try { const bucketName = 'node-sdk-test-bucket'; // 上传后的对象所在目录 const objectDirName = 'example_dir/'; // 上传本地 example_dir 文件夹下所有文件 const localDirPath = './example_dir/'; const localDirAbsolutePath = path.resolve(localDirPath) + '/'; async function walkDir(dirPath) { for (const dirent of await fsp.readdir(dirPath, { withFileTypes: true })) { const filePath = path.resolve(dirPath, dirent.name); if (dirent.isDirectory()) { walkDir(filePath); continue; } const { data } = await client.uploadFile({ bucket: bucketName, key: objectDirName + filePath.slice(localDirAbsolutePath.length), // 上传的文件路径 file: filePath, // 上传时指定分片大小 partSize: 5 * 1024 * 1024, // 分片上传任务并发数量 taskNum: 5, }); console.log(`uploadFile ${filePath} result: `, data); } } await walkDir(localDirPath); } catch (error) { handleError(error); } } main();
断点续传上传时可通过 dataTransferStatusChange
参数接收上传进度,代码示例如下。
// 导入 SDK, 当 TOS Node.JS SDK 版本小于 2.5.2 请把下方 TosClient 改成 TOS 导入 import { DataTransferType, TosClient, TosClientError, TosServerError } from '@volcengine/tos-sdk'; // 创建客户端 const client = new TosClient({ accessKeyId: process.env['TOS_ACCESS_KEY'], accessKeySecret: process.env['TOS_SECRET_KEY'], region: "Provide your region", // 填写 Bucket 所在地域。以华北2(北京)为例,则 "Provide your region" 填写为 cn-beijing。 endpoint: "Provide your endpoint", // 填写域名地址 }); function handleError(error) { if (error instanceof TosClientError) { console.log('Client Err Msg:', error.message); console.log('Client Err Stack:', error.stack); } else if (error instanceof TosServerError) { console.log('Request ID:', error.requestId); console.log('Response Status Code:', error.statusCode); console.log('Response Header:', error.headers); console.log('Response Err Code:', error.code); console.log('Response Err Msg:', error.message); } else { console.log('unexpected exception, message: ', error); } } async function main() { try { const bucketName = 'node-sdk-test-bucket'; const objectName = 'example_dir/multipartExample'; // 本地 example_dir 文件夹下的 multipartExample 文件 const filePath = './example_dir/multipartExample'; const { data } = await client.uploadFile({ bucket: bucketName, key: objectName, // 上传的文件路径 file: filePath, // 上传时指定分片大小 partSize: 5 * 1024 * 1024, // 分片上传任务并发数量 taskNum: 5, // 通过自定义方式设置回调函数查看上传进度 dataTransferStatusChange: (event) => { if (event.type === DataTransferType.Started) { console.log('Data Transfer Started'); } else if (event.type === DataTransferType.Rw) { const percent = ((event.consumedBytes / event.totalBytes) * 100).toFixed(2); console.log(`Once Read:${event.rwOnceBytes},ConsumerBytes/TotalBytes: ${event.consumedBytes}/${event.totalBytes},${percent}%`); } else if (event.type === DataTransferType.Succeed) { const percent = ((event.consumedBytes / event.totalBytes) * 100).toFixed(2); console.log(`Data Transfer Succeed, ConsumerBytes/TotalBytes:${event.consumedBytes}/${event.totalBytes},${percent}%`); } else if (event.type === DataTransferType.Failed) { console.log('Data Transfer Failed'); } }, }); console.log('uploadFile result', data); } catch (error) { handleError(error); } } main();
以下代码用于自定义断点续传上传回调函数。
// 导入 SDK, 当 TOS Node.JS SDK 版本小于 2.5.2 请把下方 TosClient 改成 TOS 导入 import { UploadEventType, TosClient, TosClientError, TosServerError } from '@volcengine/tos-sdk'; // 创建客户端 const client = new TosClient({ accessKeyId: process.env['TOS_ACCESS_KEY'], accessKeySecret: process.env['TOS_SECRET_KEY'], region: "Provide your region", // 填写 Bucket 所在地域。以华北2(北京)为例,则 "Provide your region" 填写为 cn-beijing。 endpoint: "Provide your endpoint", // 填写域名地址 }); function handleError(error) { if (error instanceof TosClientError) { console.log('Client Err Msg:', error.message); console.log('Client Err Stack:', error.stack); } else if (error instanceof TosServerError) { console.log('Request ID:', error.requestId); console.log('Response Status Code:', error.statusCode); console.log('Response Header:', error.headers); console.log('Response Err Code:', error.code); console.log('Response Err Msg:', error.message); } else { console.log('unexpected exception, message: ', error); } } async function main() { try { const bucketName = 'node-sdk-test-bucket'; const objectName = 'example_dir/multipartExample'; // 本地 example_dir 文件夹下的 multipartExample 文件 const filePath = './example_dir/multipartExample'; const { data } = await client.uploadFile({ bucket: bucketName, key: objectName, // 上传的文件路径 file: filePath, // 上传时指定分片大小 partSize: 5 * 1024 * 1024, // 分片上传任务并发数量 taskNum: 5, // 事件监听回调 uploadEventChange: (event) => { switch (event.type) { case UploadEventType.createMultipartUploadSucceed: { console.log(`Upload to ${event.bucket} ${event.key} create multipart upload success, upload id:${event.uploadId}`); break; } case UploadEventType.createMultipartUploadFailed: { console.log(`Upload to ${event.bucket} ${event.key} create multipart upload fail, upload id:${event.uploadId}`); break; } case UploadEventType.uploadPartSucceed: { console.log(`Upload to${event.bucket} ${event.key} part success, UploadPartInfo:%o`, event.uploadPartInfo); break; } case UploadEventType.uploadPartAborted: { console.log(`Upload to ${event.bucket} ${event.key} part aborted, upload id:${event.uploadId}`); break; } case UploadEventType.uploadPartFailed: { console.log(`Upload to ${event.bucket} ${event.key} part fail, upload id:${event.uploadId}`); break; } case UploadEventType.completeMultipartUploadSucceed: { console.log(`Upload to ${event.bucket} ${event.key} success, upload id:${event.uploadId}`); break; } case UploadEventType.completeMultipartUploadFailed: { console.log(`Upload to ${event.bucket} ${event.key} fail, upload id:${event.uploadId}, err: %o`, event.err); break; } } }, }); console.log('uploadFile result', data); } catch (error) { handleError(error); } } main();
断点续传上传时可以通过客户端使用 tos.RateLimiter 接口对所占用的带宽进行限制,代码如下所示。
// 导入 SDK, 当 TOS Node.JS SDK 版本小于 2.5.2 请把下方 TosClient 改成 TOS 导入 import { createDefaultRateLimiter, DataTransferType, TosClient, TosClientError, TosServerError } from '@volcengine/tos-sdk'; // 创建客户端 const client = new TosClient({ accessKeyId: process.env['TOS_ACCESS_KEY'], accessKeySecret: process.env['TOS_SECRET_KEY'], region: "Provide your region", // 填写 Bucket 所在地域。以华北2(北京)为例,则 "Provide your region" 填写为 cn-beijing。 endpoint: "Provide your endpoint", // 填写域名地址 }); function handleError(error) { if (error instanceof TosClientError) { console.log('Client Err Msg:', error.message); console.log('Client Err Stack:', error.stack); } else if (error instanceof TosServerError) { console.log('Request ID:', error.requestId); console.log('Response Status Code:', error.statusCode); console.log('Response Header:', error.headers); console.log('Response Err Code:', error.code); console.log('Response Err Msg:', error.message); } else { console.log('unexpected exception, message: ', error); } } async function main() { try { const bucketName = 'node-sdk-test-bucket'; const objectName = 'example_dir/multipartExample'; // 本地 example_dir 文件夹下的 multipartExample 文件 const filePath = './example_dir/multipartExample'; const rateLimit1M = 1024; const { data } = await client.uploadFile({ bucket: bucketName, key: objectName, // 上传的文件路径 file: filePath, // 上传时指定分片大小 partSize: 5 * 1024 * 1024, // 分片上传任务并发数量 taskNum: 5, // 上传对象并在客户端限制上传速度为 1M/s rateLimiter: createDefaultRateLimiter(rateLimit1M, rateLimit1M), // 通过自定义方式设置回调函数查看上传进度 dataTransferStatusChange: (event) => { if (event.type === DataTransferType.Started) { console.log('Data Transfer Started'); } else if (event.type === DataTransferType.Rw) { const percent = ((event.consumedBytes / event.totalBytes) * 100).toFixed(2); console.log(`Once Read:${event.rwOnceBytes},ConsumerBytes/TotalBytes: ${event.consumedBytes}/${event.totalBytes},${percent}%`); } else if (event.type === DataTransferType.Succeed) { const percent = ((event.consumedBytes / event.totalBytes) * 100).toFixed(2); console.log(`Data Transfer Succeed, ConsumerBytes/TotalBytes:${event.consumedBytes}/${event.totalBytes},${percent}%`); } else if (event.type === DataTransferType.Failed) { console.log('Data Transfer Failed'); } }, }); console.log('uploadFile result', data); } catch (error) { handleError(error); } } main();
以下代码用于在运行时取消正在执行的断点续传上传任务。
// 导入 SDK, 当 TOS Node.JS SDK 版本小于 2.5.2 请把下方 TosClient 改成 TOS 导入 import { CancelToken, TosClient, TosClientError, TosServerError } from '@volcengine/tos-sdk'; // 创建客户端 const client = new TosClient({ accessKeyId: process.env['TOS_ACCESS_KEY'], accessKeySecret: process.env['TOS_SECRET_KEY'], region: "Provide your region", // 填写 Bucket 所在地域。以华北2(北京)为例,则 "Provide your region" 填写为 cn-beijing。 endpoint: "Provide your endpoint", // 填写域名地址 }); function handleError(error) { if (error instanceof TosClientError) { console.log('Client Err Msg:', error.message); console.log('Client Err Stack:', error.stack); } else if (error instanceof TosServerError) { console.log('Request ID:', error.requestId); console.log('Response Status Code:', error.statusCode); console.log('Response Header:', error.headers); console.log('Response Err Code:', error.code); console.log('Response Err Msg:', error.message); } else { console.log('unexpected exception, message: ', error); } } async function main() { try { const bucketName = 'node-sdk-test-bucket'; const objectName = 'example_dir/multipartExample'; // 本地 example_dir 文件夹下的 multipartExample 文件 const filePath = './example_dir/multipartExample'; // 生成 cancelTokenSource const cancelTokenSource = CancelToken.source(); client.uploadFile({ bucket: bucketName, key: objectName, // 上传的文件路径 file: filePath, // 上传时指定分片大小 partSize: 5 * 1024 * 1024, // 注入 cancelToken cancelToken: cancelTokenSource.token, }); // 1秒后取消任务 setTimeout(() => { cancelTokenSource.cancel(); console.log('cancel request'); }, 1000); } catch (error) { handleError(error); } } main();