OSS提供的分片上传(Multipart Upload)功能,将要上传的较大文件(Object)分成多个数据块(Part)来分别上传,上传完成后再调用CompleteMultipartUpload接口将这些Part组合成一个Object来达到断点续传的效果。
背景信息
当需要上传的文件较大时,您可以通过MultipartUpload接口进行分片上传。分片上传是指将要上传的文件分成多个数据块(Part)来分别上传。当其中一些分片上传失败后,OSS将保留上传进度记录,再次重传时只需要上传失败的分片,而不需要重新上传整个文件。一般大于100 MB的文件,建议采用分片上传的方法,通过断点续传和重试,提高上传成功率。
在使用MultipartUpload接口时,如果遇到ConnectionTimeoutError
超时问题,业务方需自行处理超时逻辑。例如通过缩小分片大小、增加超时时间、重试请求或者捕获ConnectionTimeoutError
错误等方法处理超时。更多信息,请参见网络错误处理。
分片上传涉及的相关参数说明请参见下表。
类型 | 参数 | 说明 |
---|---|---|
必选参数 | name {String} | Object的名称。即不包括Bucket名称在内的Object的完整路径。 |
file {String|File} | 表示文件路径或者HTML5文件。 | |
[options] {Object} 可选参数 | [checkpoint] {Object} | 记录本地分片上传结果的文件。开启断点续传功能时需要设置此参数,上传过程中的进度信息会保存在该文件中,如果某一分片上传失败,再次上传时会根据文件中记录的点继续上传。上传完成后,该文件会被删除。 |
[parallel] {Number} | 并发上传的分片个数,默认为5。无特殊需求,不需要手动设置此参数。 | |
[partSize] {Number} | 指定上传的每个分片的大小,范围为100 KB~5 GB。单个分片默认大小为1 * 1024 * 1024(即1 MB)。无特殊需求,不需要手动设置此参数。 | |
[progress] {Function} | 表示进度回调函数,用于获取上传进度,可以是async的函数形式。回调函数包含三个参数:
|
|
[meta] {Object} | 用户自定义的Header meta信息,Header前缀为x-oss-meta- 。 |
|
[mime] {String} | 设置Content-Type请求头。 | |
[headers] {Object} | 其他Header。更多信息,请参见RFC 2616。其中:
|
以下示例代码中的catch语法,请自行学习es6 promise、async/await。 SDK的使用方式,请参见安装。
分片上传完整示例
以下通过一个完整的示例对分片上传的流程进行逐步解析:
const OSS = require('ali-oss'); const client = new OSS({ // region以杭州为例(oss-cn-hangzhou),其他region按实际情况填写。 region: '<Your region>', // 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。 accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: '<Your bucket name>', }); const progress = (p, _checkpoint) => { console.log(p); // Object的上传进度。 console.log(_checkpoint); // 分片上传的断点信息。 }; // 开始分片上传。 async function multipartUpload() { try { // object-name可以定义为文件名(例如file.txt)或目录(例如abc/test/file.txt)的形式,实现将文件上传至Bucket根目录或Bucket下的指定目录。 const result = await client.multipartUpload('<Object Name>', 'file-object', { progress, // meta是用户自定义的元数据,通过head接口可以获取到Object的meta数据。 meta: { year: 2020, people: 'test', }, }); console.log(result); const head = await client.head('object-name'); console.log(head); } catch (e) { // 捕获超时异常。 if (e.code === 'ConnectionTimeoutError') { console.log('TimeoutError'); // do ConnectionTimeoutError operation } console.log(e); } } multipartUpload();
取消分片上传事件
您可以调用client.abortMultipartUpload
方法来取消分片上传事件。当一个分片上传事件被取消后,无法再使用这个uploadId做任何操作,已经上传的分片数据会被删除。
以下代码用于取消分片上传事件。
const OSS = require('ali-oss'); const client = new OSS({ // region以杭州为例(oss-cn-hangzhou),其他region按实际情况填写。 region: '<Your region>', // 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。 accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: '<Your bucket name>', }); async function abortMultipartUpload() { const name = '<Object Name>'; // Object所在Bucket的完整路径。 const uploadId = '<Upload Id>'; // 分片上传uploadId。 const result = await client.abortMultipartUpload(name, uploadId); console.log(result); } abortMultipartUpload();
列举分片上传事件
调用client.listUploads
方法列举出分片上传事件示例代码如下:
const OSS = require('ali-oss'); const client = new OSS({ // region以杭州为例(oss-cn-hangzhou),其他region按实际情况填写。 region: '<Your region>', // 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。 accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: '<Your bucket name>', }); async function listUploads(query = {}) { // query参数支持prefix、marker、delimiter、upload-id-marker和max-uploads。 const result = await client.listUploads(query); result.uploads.forEach(upload => { console.log(upload.uploadId); // 分片上传的uploadId。 console.log(upload.name); // 将所有上传完成后的分片(Part)组合为一个完整的Object,并指定Object所在Bucket的完整路径。 }); } const query = { 'max-uploads': 1000, // 限定此次返回Multipart Uploads事件的最大数目。max-uploads默认值和最大值均为1000。 }; listUploads(query);
列举已上传的分片
调用client.listParts
方法列举指定uploadId下所有已经上传成功的分片。
- 简单列举已上传的分片
以下代码用于简单列举已上传的分片:
const OSS = require('ali-oss'); const client = new OSS({ // region以杭州为例(oss-cn-hangzhou),其他region按实际情况填写。 region: '<Your region>', // 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。 accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: '<Your bucket name>', }); async function listParts() { const query = { 'max-parts': 1000, // 指定OSS响应中的最大分片(Part)数目。max-parts默认值和最大值均为1000。 }; const result = await client.listParts('<Object Name>', '<Upload Id>', query); result.parts.forEach(part => { console.log(part.PartNumber); console.log(part.LastModified); console.log(part.ETag); console.log(part.Size); }); } listParts();
- 列举所有已上传的分片
默认情况下,
client.listParts
只能一次列举1000个分片。当分片数量大于1000时,请使用以下代码列举所有已上传的分片。const OSS = require('ali-oss') const client = new OSS({ // region以杭州为例(oss-cn-hangzhou),其他region按实际情况填写。 region: '<Your region>', // 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录RAM控制台创建RAM账号。 accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: '<Your bucket name>', }); async function listParts() { const query = { 'max-parts': 1000, // 设置OSS响应中的最大分片(Part)数目。max-parts默认值和最大值均为1000。 }; let result; do { result = await client.listParts('<Object Name>', '<Upload Id>', query); // 设置列举分片的起始位置。 query['part-number-marker'] = result.nextPartNumberMarker; result.parts.forEach(part => { console.log(part.PartNumber); console.log(part.LastModified); console.log(part.ETag); console.log(part.Size); }); } while (result.isTruncated === "true"); } listParts();