上传Object
在BOS中,用户操作的基本数据单元是Object。Bucket中的Object数量不限,但单个Object最大允许存储5TB的数据。
Object包含Key、Meta和Data。其中:
- Key是Object的名字;
- Meta是用户对该Object的描述,由一系列Name-Value对组成;
- Data是Object的数据。
BOS JavaScript SDK提供了丰富的文件上传接口,可以通过以下方式上传文件:
- 简单上传
- 追加上传
- 分块上传
- 断点续传上传
Object的命名规范如下:
- 使用UTF-8编码。
- 长度必须在1-1023字节之间。
- 首字母不能为'/',不能包含'@'字符,'@'用于图片处理接口。
简单上传
在简单上传的场景中,JS SDK 支持以数据流方式、以字符串方式、以指定文件形式(仅支持Node.js环境)、以blob对象形式(仅支持浏览器环境)执行Object上传。 分别对应 putObject 、 putObjectFromString 、putObjectFromFile 、putObjectFromBlob 方法。
-
基本流程
- 创建BosClient。
- 调用putObject()相关方法
-
示例代码
JavaScript1function done(response) { 2 // 上传完成 3} 4function fail(fail) { 5 // 上传失败 6} 7// 以buffer形式上传 8var buffer = new Buffer('hello world'); 9client.putObject(bucket, object, buffer) 10 .then(done) 11 .catch(fail); 12 13// 以字符串形式上传 14client.putObjectFromString(bucket, object, 'hello world') 15 .then(done) 16 .catch(fail); 17 18// 以文件形式上传,仅支持Node.js环境 19client.putObjectFromFile(bucket, object, <path-to-file>) 20 .then(done) 21 .catch(fail); 22 23// 以blob对象形式上传,仅支持浏览器环境 24client.putObjectFromBlob(bucket, object, <blob对象>) 25 .then(done) 26 .catch(fail);
说明:Object以文件的形式上传到BOS中,putObject函数支持不超过5GB的Object上传。在putObject请求处理成功后,BOS会在Header中返回Object的ETag作为文件标识。
追加上传
上文介绍的简单上传方式,创建的Object都是Normal类型,用户不可再进行追加写,这在日志、视频监控、视频直播等数据复写较频繁的场景中使用不方便。
正因如此,百度智能云BOS特别支持了AppendObject,即以追加写的方式上传文件。通过AppendObject操作创建的Object类型为Appendable Object,可以对该Object追加数据。AppendObject大小限制为0~5G。
1let bucketName = "yourbucket";
2let appendKey = "appendObjectKey";
3
4// 首次上传时,offset设置为null
5client.appendObjectFromString(bucketName,appendKey,"firstContent",null)
6.then(function(response){
7 // 从响应头中获取offset偏移量
8 var offset = + response.http_headers['x-bce-next-append-offset'];
9 // 第二次追加上传时,指定上面获取到的offset传入
10 client.appendObjectFromString(bucketName, appendKey, "appendContent", offset);
11});
分块上传
除了通过putObject()方法上传文件到BOS以外,BOS还提供了另外一种上传模式:分块上传(Multipart Upload)。用户可以在如下的应用场景内(但不仅限于此),使用分块上传模式,如:
- 需要支持断点上传。
- 上传超过5GB大小的文件。
- 网络条件较差,和BOS的服务器之间的连接经常断开。
- 需要流式地上传文件。
- 上传文件之前,无法确定上传文件的大小。
分块上传比直接上传稍微复杂一点,分块上传需要分为三个阶段:
- 开始上传(initiateMultipartUpload)
- 上传分块(uploadPartFromBlob)
- 上传完成(completeMultipartUpload)
浏览器端代码示例
对文件进行分块
1let options = {
2 'Content-Type': 'application/json', // 添加http header
3 'Cache-Control': 'public, max-age=31536000', // 指定缓存指令
4 'Content-Disposition': 'attachment; filename="example.jpg"', // 指示回复的内容该以何种形式展示
5
6 'x-bce-meta-foo1': 'bar1', // 添加自定义meta信息
7 'x-bce-meta-foo2': 'bar2', // 添加自定义meta信息
8 'x-bce-meta-foo3': 'bar3' // 添加自定义meta信息
9};
10let PART_SIZE = 5 * 1024 * 1024; // 指定分块大小
11
12function getTasks(file, uploadId, bucketName, key) {
13 let leftSize = file.size;
14 let offset = 0;
15 let partNumber = 1;
16
17 let tasks = [];
18
19 while (leftSize > 0) {
20 let partSize = Math.min(leftSize, PART_SIZE);
21 tasks.push({
22 file: file,
23 uploadId: uploadId,
24 bucketName: bucketName,
25 key: key,
26 partNumber: partNumber,
27 partSize: partSize,
28 start: offset,
29 stop: offset + partSize - 1
30 });
31
32 leftSize -= partSize;
33 offset += partSize;
34 partNumber += 1;
35 }
36 return tasks;
37}
处理每个分块的上传逻辑
1function uploadPartFile(state, client) {
2 return function(task, callback) {
3 let blob = task.file.slice(task.start, task.stop + 1);
4 client.uploadPartFromBlob(task.bucketName, task.key, task.uploadId, task.partNumber, task.partSize, blob)
5 .then(function(res) {
6 ++state.loaded;
7 callback(null, res);
8 })
9 .catch(function(err) {
10 callback(err);
11 });
12 };
13}
初始化uploadID,开始上传分块,并完成上传
1let uploadId;
2client.initiateMultipartUpload(bucket, key, options)
3 .then(function(response) {
4 uploadId = response.body.uploadId; // 开始上传,获取服务器生成的uploadId
5
6 let deferred = sdk.Q.defer();
7 let tasks = getTasks(blob, uploadId, bucket, key);
8 let state = {
9 lengthComputable: true,
10 loaded: 0,
11 total: tasks.length
12 };
13
14 // 为了管理分块上传,使用了async(https://github.com/caolan/async)库来进行异步处理
15 let THREADS = 2; // 同时上传的分块数量
16 async.mapLimit(tasks, THREADS, uploadPartFile(state, client), function(err, results) {
17 if (err) {
18 deferred.reject(err);
19 } else {
20 deferred.resolve(results);
21 }
22 });
23 return deferred.promise;
24 })
25 .then(function(allResponse) {
26 let partList = [];
27 allResponse.forEach(function(response, index) {
28 // 生成分块清单
29 partList.push({
30 partNumber: index + 1,
31 eTag: response.http_headers.etag
32 });
33 });
34 return client.completeMultipartUpload(bucket, key, uploadId, partList); // 完成上传
35 })
36 .then(function (res) {
37 // 上传完成
38 })
39 .catch(function (err) {
40 // 上传失败,添加您的代码
41 console.error(err);
42 });
Node.js端代码示例
对文件进行分块,并初始化UploadID,上传分块
1let options = {
2 'Content-Type': 'application/json', // 添加http header
3 'Cache-Control': 'public, max-age=31536000', // 指定缓存指令
4 'Content-Disposition': 'attachment; filename="example.jpg"', // 指示回复的内容该以何种形式展示
5
6 'x-bce-meta-foo1': 'bar1', // 添加自定义meta信息
7 'x-bce-meta-foo2': 'bar2', // 添加自定义meta信息
8 'x-bce-meta-foo3': 'bar3' // 添加自定义meta信息
9};
10let PART_SIZE = 5 * 1024 * 1024; // 指定分块大小
11let uploadId;
12client.initiateMultipartUpload(bucket, key, options)
13 .then(function(response) {
14 uploadId = response.body.uploadId; // 开始上传,获取服务器生成的uploadId
15 let deferred = sdk.Q.defer();
16 let blob = {
17 // 使用fs文件库获取文件大小
18 size: fs.statSync(localFileName).size,
19 filename: localFileName
20 }
21 let tasks = getTasks(blob, uploadId, bucket, key);
22 let state = {
23 lengthComputable: true,
24 loaded: 0,
25 total: tasks.length
26 };
27 // 为了管理分块上传,使用了async(https://github.com/caolan/async)库来进行异步处理
28 let THREADS = 2; // 同时上传的分块数量
29 async.mapLimit(tasks, THREADS, uploadPartFile(state, client), function(err, results) {
30 if (err) {
31 deferred.reject(err);
32 } else {
33 deferred.resolve(results);
34 }
35 });
36 return deferred.promise;
37 })
38 .then(function(allResponse) {
39 let partList = [];
40 allResponse.forEach(function(response, index) {
41 // 生成分块清单
42 partList.push({
43 partNumber: index + 1,
44 eTag: response.http_headers.etag
45 });
46 });
47 return client.completeMultipartUpload(bucket, key, uploadId, partList); // 完成上传
48 })
49 .then(function (res) {
50 // 上传完成
51 })
52 .catch(function (err) {
53 // 上传失败,添加您的代码
54 console.error(err);
55 });
56
57function getTasks(file, uploadId, bucketName, key) {
58 let leftSize = file.size;
59 let offset = 0;
60 let partNumber = 1;
61 let tasks = [];
62 while (leftSize > 0) {
63 let partSize = Math.min(leftSize, PART_SIZE);
64 tasks.push({
65 file: file.filename,
66 uploadId: uploadId,
67 bucketName: bucketName,
68 key: key,
69 partNumber: partNumber,
70 partSize: partSize,
71 start: offset,
72 stop: offset + partSize - 1
73 });
74
75 leftSize -= partSize;
76 offset += partSize;
77 partNumber += 1;
78 }
79 return tasks;
80}
81
82
83function uploadPartFile(state, client) {
84 return function(task, callback) {
85 console.log("task: ", task)
86 return client.uploadPartFromFile(task.bucketName, task.key, task.uploadId, task.partNumber, task.partSize, task.file , task.start)
87 .then(function(res) {
88 ++state.loaded;
89 console.log("ok")
90 callback(null, res);
91 })
92 .catch(function(err) {
93 console.log("bad")
94 callback(err);
95 });
96 };
97}
取消分块上传事件
用户可以使用abortMultipartUpload方法取消分块上传。
1client.abortMultipartUpload(<BucketName>, <Objectkey>, <UploadID>);
获取未完成的分块上传事件
用户可以使用listMultipartUploads方法获取Bucket内未完成的分块上传事件。
1client.listMultipartUploads(<bucketName>)
2 .then(function (response) {
3 // 遍历所有上传事件
4 for (var i = 0; i < response.body.multipartUploads.length; i++) {
5 console.log(response.body.multipartUploads[i].uploadId);
6 }
7 });
获取所有已上传的块信息
用户可以使用listParts方法获取某个上传事件中所有已上传的块。
1client.listParts(<bucketName>, <key>, <uploadId>)
2 .then(function (response) {
3 // 遍历所有上传事件
4 for (var i = 0; i < response.body.parts.length; i++) {
5 console.log(response.body.parts[i].partNumber);
6 }
7 });
断点续传上传
当用户向BOS上传大文件时,如果网络不稳定或者遇到程序崩等情况,则整个上传就失败了,失败前已经上传的部分也作废,用户不得不重头再来。这样做不仅浪费资源,在网络不稳定的情况下,往往重试多次还是无法完成上传。基于上述场景,BOS提供了断点续传上传的能力,主要利用了分块上传的能力,将待上传的文件拆分成多个分块(Part),然后分别上传这些分块,当所有分块全部上传完成后,BOS将请求者上传的所有分块组合成完整的Object。
putSuperObject
1.0.1-beta.2
及以上版本支持
JavaScript SDK提供了putSuperObject
方法,对分块上传相关的API做了高级封装,支持分上传任务暂停、恢复、取消、分片并发数设置,失败重试等功能。
请求头
除公共头域外,无其他特殊请求头
初始化参数
参数名称 | 说明 | 类型 | 必填 | 默认值 | 示例值 |
---|---|---|---|---|---|
bucketName | 存储桶名称 | string |
是 | - | "bucket001" |
objectName | 上传后对象名称 | string |
是 | - | "file001" |
data | 上传数据, 类型为string时表示文件路径,还支持Buffer和Blob对象 | string | Buffer | Blob |
是 | - | - |
StorageClass | 文件存储类型 | "STANDARD" | "STANDARD_IA" | "COLD" | "ARCHIVE" | "MAZ_STANDARD" | "MAZ_STANDARD_IA" |
否 | "STANDARD" |
"STANDARD" |
chunkSize | 上传文件分片默认体积, 单位为bytes | number |
否 | 5 * 1024 ** 2(5MB) | 1048576 |
partConcurrency | 分片并发数量 | number | 否 | 5 | 5 |
ContentLength | 文件大小,单位为bytes,非必填,内部会基于自动计算 | string |
否 | - | 1048576 |
ContentType | 文件媒体类型,非必填,内部会基于objectName字段自动生成 | string |
否 | - | "application/x-gtar" |
uploadId | 分片上传任务ID,非必填,当需要从断点恢复任务时,需要传入该参数 | string |
否 | - | "a44cc9bab11cbd156984767aad637851" |
onProgress | 上传进度回调函数 | ProgressCallback |
否 | - | - |
onStateChange | 任务状态变化回调函数 | StateChangeCallback |
否 | - | - |
ProgressCallback
1type ProgressCallback = (
2 /* 当前上传速度 */
3 speed: string,
4 /* 上传进度,保留4位小数 */
5 progress: number,
6 /* 上传进度-百分比 */
7 percent: string,
8 /* 已上传字节数 */
9 uploadedBytes: number,
10 /* 文件总字节数 */
11 totalBytes
12) => void
StateChangeCallback
1type StateChangeCallback = (
2 /* 状态 */
3 state: string,
4 /* 如果上传失败会传递失败的message,上传成功会返回上传后的地址 */
5 options: {
6 message: string;
7 data: Record<string, any> | null
8 }
9) => void;
状态
"inited"
:任务初始化完成"running"
:任务队列运行中"paused"
:任务队列暂停"completed"
:任务完成,上传结束"cancelled"
:任务取消,上传结束"failed"
:任务异常,上传结束
Node.js端代码示例
1const sdk = require('@baiducloud/sdk');
2const client = new sdk.BosClient({
3 endpoint: 'http://bj.bcebos.com',
4 credentials: {
5 ak: "<Your Access Key>",
6 sk: "<Your Secret Key>"
7 }
8});
9// 存储桶名称
10const bucketName = "<Your Bucket Name>";
11// 上传后文件名称
12const objectName = 'demo.tgz';
13// 本地文件路径
14const data = '/Mock/path/to/local/file/demo.tgz';
15
16// 初始化上传任务
17const SuperUploadTask = client.putSuperObject({
18 // 桶名称
19 bucketName,
20 // 上传后对象名称
21 objectName,
22 // 上传数据, 类型为string时表示文件路径
23 data,
24 // 分片并发数
25 partConcurrency: 2,
26 // 上传进度回调函数
27 onProgress: (options) => {
28 const {speed, progress, percent, uploadedBytes, totalBytes} = options;
29 console.log(options);
30 },
31 // 状态变化回调函数
32 onStateChange: (state, data) => {
33 if (state === 'completed') {
34 console.log('上传成功');
35 } else if (state === 'failed') {
36 console.error('上传失败,失败原因:' + data.message);
37 } else if (state === 'cancelled') {
38 console.log('上传任务取消');
39 } else if (state === 'inited') {
40 console.log('上传任务初始化完成');
41 } else if (state === 'running') {
42 console.log('上传任务开始运行...');
43 } else if (state === 'paused') {
44 console.log('上传任务已暂停');
45 }
46 }
47});
48
49// 启动上传任务
50const tasks = SuperUploadTask.start();
51console.log('切分任务: ', tasks);
52
53// 暂停上传任务
54setTimeout(() => {
55 SuperUploadTask.pause();
56}, 5000);
57
58// 恢复上传任务
59setTimeout(() => {
60 SuperUploadTask.resume();
61}, 15000);
62
63// 取消上传任务
64setTimeout(async () => {
65 const result = SuperUploadTask.cancel();
66 console.log(result ? '任务取消成功' : '任务取消失败');
67}, 25000);
浏览器端代码示例
1<html>
2 <head>
3 <meta charset="utf-8" />
4 <title>SuperUpload测试</title>
5 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/amis/6.2.2/sdk.min.css" integrity="sha512-9yikVhRqNeq1rypIzAFKR8CA2uG8V5gYppoDKK4xx+7eoLXJsEm+f9QN0++xqHvrOxxvb93uiipgYk9uEW7RlA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
6 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/amis/6.2.2/cxd.min.css" integrity="sha512-9yikVhRqNeq1rypIzAFKR8CA2uG8V5gYppoDKK4xx+7eoLXJsEm+f9QN0++xqHvrOxxvb93uiipgYk9uEW7RlA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
7 <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/simple-notify@1.0.4/dist/simple-notify.css" />
8 </head>
9 <body>
10 <div id="root"></div>
11 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js" integrity="sha512-v2CJ7UaYy4JwqLDIrZUI/4hqeoQieOmAZNXBeQyjo21dadnwR+8ZaIJVT8EE2iyI61OV8e6M8PP2/4hpQINQ/g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
12 <script src="https://cdn.jsdelivr.net/npm/simple-notify@1.0.4/dist/simple-notify.min.js"></script>
13 <script src="https://cdnjs.cloudflare.com/ajax/libs/amis/6.2.2/sdk.min.js" integrity="sha512-BpMIHWCtAUDARuH/qnGH6eBxoOv4l0i4Y9/9f6vnGVDNnPqbWCZoPgk3/KvY6NuOb6cAPFmqVN1R2sXz7Z3VcQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
14 <script src="https://bce.bdstatic.com/lib/@baiducloud/sdk/1.0.1-beta.2/baidubce-sdk.bundle.min.js" ></script>
15 <script>
16 (async function () {
17 // 实例化BOS SDK
18 const client = new window.baidubce.sdk.BosClient({
19 endpoint: 'http://bj.bcebos.com',
20 credentials: {
21 ak: "<Your Access Key>",
22 sk: "<Your Secret Key>"
23 }
24 });
25 // 实例化BOS SDK
26 const bucketName = '<Your Bucket Name>';
27 // 上传任务实例
28 let SuperUpload;
29 // 进度信息
30 let p1 = 0;
31
32 // 消息弹窗
33 function pushNotify({status, title, text}) {
34 new Notify({
35 status: status || 'success',
36 title: title,
37 text: text,
38 distance: 200,
39 position: 'x-center'
40 });
41 }
42
43 // 获取任务实例
44 function getInstance() {
45 if (SuperUpload) {
46 pushNotify({title: '获取实例信息', text: '实例信息获取成功'});
47 } else {
48 pushNotify({status: 'error', title: '获取实例信息', text: '实例信息获取失败'});
49 }
50 }
51
52 async function start() {
53 const files = $('#file')?.[0]?.files;
54
55 if (!files || files.length === 0) {
56 pushNotify({status: 'error', title: '上传', text: '请先选择文件'});
57 return;
58 }
59
60 const file = files[0];
61 let reader = new FileReader();
62 let rs = reader.readAsArrayBuffer(file);
63 let blob = null;
64
65 // 将文件读取为Blob对象
66 reader.onload = async e => {
67 if (typeof e.target.result === 'object') {
68 blob = new Blob([e.target.result]);
69 } else {
70 blob = e.target.result;
71 }
72
73 SuperUpload = client.putSuperObject({
74 bucketName,
75 objectName: file.name,
76 ContentLength: file.size,
77 ContentType: file.type,
78 data: blob,
79 partConcurrency: 2,
80 onProgress: options => {
81 const {speed, progress, uploadedBytes, totalBytes} = options;
82
83 console.log(options);
84 amisScoped.updateProps({
85 data: {p1: progress * 100}
86 });
87 },
88 onStateChange: (state, data) => {
89 if (state === 'completed') {
90 pushNotify({title: '上传', text: '上传成功'});
91 console.log(data);
92 } else if (state === 'failed') {
93 pushNotify({status: 'error', title: '上传失败', text: data.message});
94 } else if (state === 'cancelled') {
95 pushNotify({title: '上传', text: '上传任务取消'});
96 } else if (state === 'inited') {
97 pushNotify({title: '上传', text: '上传任务初始化完成'});
98 } else if (state === 'running') {
99 pushNotify({title: '上传', text: '上传任务开始运行...'});
100 } else if (state === 'paused') {
101 pushNotify({title: '上传', text: '上传任务已暂停'});
102 }
103 }
104 });
105
106 const tasks = await SuperUpload.start();
107 console.log('切片列表: ', tasks);
108 };
109 }
110
111 function pause() {
112 if (SuperUpload) {
113 SuperUpload.pause();
114 } else {
115 pushNotify({status: 'error', title: '暂停', text: '实例不存在'});
116 }
117 }
118
119 function resume() {
120 if (SuperUpload) {
121 SuperUpload.resume();
122 } else {
123 pushNotify({status: 'error', title: '恢复', text: '实例不存在'});
124 }
125 }
126
127 async function cancel() {
128 if (SuperUpload) {
129 const result = await SuperUpload.cancel();
130
131 if (result) {
132 SuperUpload = undefined;
133 p1 = 0;
134
135 amisScoped.updateProps({
136 data: {p1: 0}
137 });
138 }
139 } else {
140 pushNotify({status: 'error', title: '取消任务', text: '实例不存在'});
141 }
142 }
143
144 const amis = amisRequire('amis/embed');
145 const amisJSON = {
146 type: 'page',
147 body: [
148 {
149 type: 'alert',
150 title: 'CORS配置',
151 body: '如果接口报CORS错误,请开启对应存储桶的<a href="https://cloud.baidu.com/doc/BOS/s/Dk6kqw1g8", target="__blank">CORS配置</a>',
152 level: 'warning',
153 showIcon: true,
154 className: 'mb-3'
155 },
156 {
157 type: 'custom',
158 name: 'file',
159 onMount: (dom, value, onChange, props) => {
160 const input = document.createElement('input');
161 input.setAttribute('type', 'file');
162 input.setAttribute('id', 'file');
163
164 dom.appendChild(input);
165 }
166 },
167 {
168 type: 'progress',
169 value: '${p1}',
170 style: {
171 marginTop: '20px',
172 width: '500px'
173 }
174 },
175 {
176 type: 'flex',
177 justify: 'flex-start',
178 style: {
179 marginTop: '20px'
180 },
181 items: [
182 {
183 type: 'button',
184 level: 'primary',
185 label: '获取实例',
186 style: {
187 marginRight: '10px'
188 },
189 onClick: getInstance
190 },
191 {
192 type: 'button',
193 level: 'primary',
194 label: '上传',
195 style: {
196 marginRight: '10px'
197 },
198 onClick: start
199 },
200 {
201 type: 'button',
202 level: 'primary',
203 label: '暂停',
204 style: {
205 marginRight: '10px'
206 },
207 onClick: pause
208 },
209 {
210 type: 'button',
211 level: 'primary',
212 label: '恢复',
213 style: {
214 marginRight: '10px'
215 },
216 onClick: resume
217 },
218 {
219 type: 'button',
220 level: 'danger',
221 label: '取消',
222 onClick: cancel
223 }
224 ]
225 }
226 ]
227 };
228 const amisScoped = amis.embed('#root', amisJSON, {data: {p1}});
229 })()
230 </script>
231 </body>
232</html>
设定Object的Http Header和自定义Meta数据
SDK本质上是调用后台的HTTP接口,因此BOS服务允许用户自定义Http Header。同时也允许用户对要上传的Object添加自定义Meta信息。以putObjectFromFile()函数为例,可以用以下代码来处理:
-
示例代码
JavaScript1let options = { 2 'Content-Type': 'application/json', // 添加http header 3 'Cache-Control': 'public, max-age=31536000', // 指定缓存指令 4 'Content-Disposition': 'attachment; filename="example.jpg"', // 指示回复的内容该以何种形式展示 5 6 'x-bce-meta-foo1': 'bar1', // 添加自定义meta信息 7 'x-bce-meta-foo2': 'bar2', // 添加自定义meta信息 8 'x-bce-meta-foo3': 'bar3' // 添加自定义meta信息 9} 10client.putObjectFromFile(bucket, object, <path-to-file>, options) 11 .then(done) 12 .catch(fail);
注意:自定义Meta信息的key需要以
x-bce-meta-
开头。
获取上传进度
JavaScript SDK支持在上传过程中实时提供上传进度信息,可通过监听process事件获取相关信息,所有上传相关接口均支持该功能。
-
示例代码:以putObjectFromBlob接口为例
JavaScript1 // 以blob对象形式上传,仅支持浏览器环境 2client.putObjectFromBlob(bucket, object, <blob对象>) 3 .then(done) 4 .catch(fail); 5 6client.on('progress', function() { 7 // do something 8})
同步回调
JavaScript SDK支持BOS服务端同步回调接口,通过请求头中添加x-bce-process
或者在url的query中添加x-bce-process
,指定回调的服务器地址和相关参数配置,就可以在上传完成后,让BOS服务端主动调用回调接口来达到通知客户目的。
目前仅支持普通上传(PutObject)和 完成分片上传(CompleteMultipartUpload)
- 方法一:
使用
callback
参数,SDK会帮助你处理参数并添加到请求头中
1try {
2 const res = await client.putObjectFromString('bucketName', 'fileName', 'demo-string', {
3 callback: {
4 urls: ["https://www.test.com/callback"],
5 vars: {name: 'baidu'},
6 encrypt: 'config',
7 key: 'callback1'
8 }
9 });
10
11 /* callback result */
12 console.log(res.body.callback.result);
13} catch (e) {
14 /* callback error code */
15 console.error(res.body.callback.code);
16 /* callback error message */
17 console.error(res.body.callback.message);
18}
- 方法二:
自行处理参数,将
"x-bce-process"
参数和值添加到请求头中
1try {
2 const res = await client.putObjectFromString('bucketName', 'fileName', 'demo-string', {
3 'x-bce-process': 'callback/callback,u_WyJodHRwczovL3d3dy50ZXN0LmNvbS9jYWxsYmFjayJd,m_sync,v_eyJuYW1lIjoiYmFpZHUifQ'
4 });
5
6 /* callback result */
7 console.log(res.body.callback.result);
8} catch (e) {
9 /* callback error code */
10 console.error(res.body.callback.code);
11 /* callback error message */
12 console.error(res.body.callback.message);
13}