百度对象存储BOS(Baidu Object Storage),是百度开放云对外提供的稳定、安全、高效以及高扩展存储服务,支持文本、多媒体、二进制等任何类型的数据存储。数据多地域跨集群的存储,以实现资源统一利用,降低使用难度,提高工作效率。
百度开放云目前开通了多区域支持,请参考区域选择说明。BOS 目前支持“华北-北京”和“华南-广州”两个区域。
BOS API的服务域名为:
Region | Protocol | Endpoint |
---|---|---|
BJ | HTTP or HTTPS | http(s)://bj.bcebos.com |
GZ | HTTP or HTTPS | http(s)://gz.bcebos.com |
BOS API支持HTTP和HTTPS两种调用方式。为了提升数据的安全性,建议通过HTTPS调用。
BosClient是BOS服务的javascript客户端,为调用者与BOS服务进行交互提供了一系列的方法。
var BosClient = baidubce.sdk.BosClient
import {BosClient} from 'bce-sdk-js'
var config = { endpoint: 'http://bos.bj.baidubce.com', credentials: { ak: '您的ak', sk: '您的sk' } }; var client = new BosClient(config);
Bucket既是BOS上的命名空间,也是计费、权限控制、日志记录等高级功能的管理实体。
Bucket的命名有以下规范:
如下代码可以新建一个Bucket:
var newBucketName = <bucketName>; // 指定Bucket的名称 client.createBucket(newBucketName) .then(function () { // 创建完成,用户添加自已的代码; }) .catch(function (error) { // 创建失败,用户添加自己的代码,处理异常 });
如下代码可以列出用户所有的Bucket:
client.listBuckets() .then(function (response) { var buckets = response.body.buckets || []; for (var i = 0 , l = buckets.length; i < l; i++) { console.log(buckets[i].name); } }) .catch(function () { // 查询失败,用户添加自己的代码,处理异常 });
若用户需要判断某个Bucket是否存在,则如下代码可以做到:
client.doesBucketExist(<bucketName>) .then(function (response) { if(response) { console.log('bucket存在'); } else { console.log('bucket不存在'); } }) .catch(function () { // 查询失败,用户添加自己的代码,处理异常 });
如下代码可以删除一个Bucket:
client.deleteBucket(<bucketName>) .then(function () { // 删除完成 }) .catch(function (error) { // 删除失败 });
复制 注意:如果Bucket不为空(即Bucket中有Object存在),则Bucket无法被删除,必须清空Bucket后才能成功删除。
如下代码将Bucket的权限设置为了private
:
client.setBucketCannedAcl(<bucketName>, 'private') .then(function () { // 设置完成 }) .catch(function (error) { // 设置失败 });
除了private
,还有public-read
和public-read-write
可以设置,它们分别对应不同的权限。具体内容可以参考《BOS API文档 使用CannedAcl方式的权限控制》。
BOS还可以实现设置指定用户对Bucket的访问权限,参考如下代码实现:
var grant_list = [ { 'grantee': [ {'id': <userId1>}, // 授权给特定用户1 {'id': <userId2>}, // 授权给特定用户2 ], 'permission': ['FULL_CONTROL'] // 设置权限为FULL_CONTROL }, { 'grantee': [ {'id': <userId3>} // 授权给特定用户1 ], 'permission': ['READ'] // 设置权限为READ } ]; client.setBucketAcl(<bucketName>, grant_list) .then(function () { // 设置完成 }) .catch(function (error) { // 设置失败 });
注意:permission中的权限设置包含三个值:READ
、WRITE
、FULL_CONTROL
,它们分别对应相关权限。具体内容可以参考《BOS API文档 上传ACL文件方式的权限控制》。
在BOS中,用户操作的基本数据单元是Object。Object包含Key、Meta和Data。其中,Key是Object的名字;Meta是用户对该Object的描述,由一系列Name-Value对组成;Data是Object的数据。
Object的命名规范如下:
BOS支持多种形式的Object上传,参考如下代码:
function done(response) { // 上传完成 } function fail(fail) { // 上传失败 } // 以字符串形式上传 client.putObjectFromString(bucket, object, 'hello world') .then(done) .catch(fail); // 以DataUrl形式上传 var dataUrl = new Buffer('hello world').toString('base64'); client.putObjectFromDataUrl(bucket, object, dataUrl) .then(done) .catch(fail); // 以文件形式上传,仅支持nodejs环境 client.putObjectFromFile(bucket, object, <path-to-file>) .then(done) .catch(fail); // 以blob对象形式上传,仅支持浏览器环境 client.putObjectFromBlob(bucket, object, <blob对象>) .then(done) .catch(fail);
Object以文件的形式上传到BOS中,以上简单上传的函数支持不超过5GB的Object上传。在上传处理成功后,BOS会在Header中返回Object的ETag作为文件标识。
sdk本质上是调用后台的HTTP接口,因此BOS服务允许用户自定义Http Header。同时也允许用户对要上传的Object添加自定义meta信息。以putObjectFromFile()
函数为例,可以用以下代码来处理:
var options = { 'Content-Length': <file.size>, // 添加http header 'Content-Type': 'application/json', // 添加http header 'x-bce-meta-foo1': 'bar1', // 添加自定义meta信息 'x-bce-meta-foo2': 'bar2', // 添加自定义meta信息 'x-bce-meta-foo3': 'bar3' // 添加自定义meta信息 } client.putObjectFromFile(bucket, object, <path-to-file>, options) .then(done) .catch(fail);
注意,自定义meta信息的key需要以x-bce-meta-
开头。
除了通过上述接口上传文件到BOS以外,BOS还提供了另外一种上传模式 —— Multipart Upload。用户可以在如下的应用场景内(但不仅限于此),使用Multipart Upload上传模式,如:
具体的api及使用方法,请参考大文件分块上传
如下代码所示:
client.listObjects(<bucketName>) .then(function (response) { var contents = response.body.contents; for (var i = 0, l = contents.length; i < l; i++) { console.log(contents[i].key); } }) .catch(function (error) { // 查询失败 });
注意:
IsTruncated
值为true
,并返回NextMarker
做为下次读取的起点。Marker
参数分次读取。用户可以通过设置listObjects
的第二个参数来完成更强大的功能,如下代码所示:
// 设置参数 var options = { delimiter: '/', marker: '123' }; client.listObjects(<bucketName>, options) .then(function (response) { var contents = response.body.contents; for (var i = 0, l = contents.length; i < l; i++) { console.log(contents[i].key); } }) .catch(function (error) { // 查询失败 });
上面代码在调用listObject
时,指定了delimiter
和marker
两个配置项,以实现更丰富的功能,下表列出了所有可设置的配置名称和作用:
名称 | 作用 |
---|---|
delimiter | 是一个用于对Object名字进行分组的字符。所有名字包含指定的前缀且第一次出现delimiter字符之间的Object作为一组元素: commonPrefixes 。 |
marker | 设定结果从marker 之后按字母排序的第一个开始返回。 |
maxKeys | 限定此次返回Object的最大数,此数值不能超过1000,如果不设定,默认为1000。 |
prefix | 限定返回的Object Key必须以prefix 作为前缀。 |
注意:
如果有Object以prefix
命名,当仅使用prefix
查询时,返回的所有Key中仍会包含以prefix
命名的Object
如果有Object以prefix
命名,当使用prefix
和delimiter
组合查询时,返回的所有Key中会有null
,Key的名字不包含prefix
前缀
用户可以通过delimiter
和prefix
配置项配合进行文件夹功能模拟。
假设Bucket中有5个文件:bos.jpg,fun/,fun/test.jpg,fun/movie/001.avi,fun/movie/007.avi,把 “/” 符号作为文件夹的分隔符。
可以通过设置prefix
配置项来获取某个目录下所有的文件:
// 设置参数 var options = { prefix: 'fun/' // 递归列出fun目录下的所有文件 }; client.listObjects(<bucketName>, options) .then(function (response) { console.log('Objects:'); var contents = response.body.contents; for (var i = 0, l = contents.length; i < l; i++) { console.log(contents[i].key); } }) .catch(function (error) { // 查询失败 });
输出:
Objects: fun/ fun/movie/001.avi fun/movie/007.avi fun/test.jpg
在prefix
和delimiter
结合的情况下,可以列出目录下的文件和子目录:
// 设置参数 var options = { prefix: 'fun/', // 列出fun目录下的所有文件和文件夹 delimiter: '/' // "/" 为文件夹的分隔符 }; client.listObjects(<bucketName>, options) .then(function (response) { console.log('Objects:'); var contents = response.body.contents; for (var i = 0, l = contents.length; i < l; i++) { console.log(contents[i].key); } console.log('CommonPrefixs:'); var commonPrefixes = response.body.commonPrefixs; for (i = 0, l = commonPrefixes.length; i < l; i++) { console.log(commonPrefixes[i]); } }) .catch(function (error) { // 查询失败 });
输出:
Objects: fun/ fun/test.jpg CommonPrefixs: fun/movie/
返回的结果中,response.body.contents
给出的是fun目录下的文件。而response.body.commonPrefixs
的列表中给出的是fun目录下的所有子文件夹。可以看出 fun/movie/001.avi , fun/movie/007.avi 两个文件并没有被列出来,因为它们属于fun文件夹下的movie目录。
用户可以通过如下代码将Object读取到一个流中:
var range = '0-100'; client.getObject(<bucketName>, <key>, range) .then(function (response) { var buffer = response.body; });
设置range为0-100表示只获取0到100字节的数据,用户可以用此功能实现文件的分段下载和断点续传。如果不设置range,刚获取整个Object。
用户可以通过如下代码将Object下载到一个文件中:
var range = '0-100'; client.getObjectToFile(<bucketName>, <key>, <filePath>, range) .then(function () { // 下载完成 });
range的用法同上。
通过getObjectMetadata方法可以只获取ObjectMetadata而不获取Object的实体。如下代码所示:
client.getObjectMetadata(<bucketName>, <key>) .then(function (response) { console.dir(response.http_headers); });
如下代码删除了一个Object:
client.deleteObject(<bucketName>, <key>);
用户可以通过copyObjectRequest实现Object的拷贝,如下代码所示:
var options = { x-bce-meta-foo1: 'bar1', // 覆盖自定义meta信息 x-bce-meta-foo2: 'bar2', // 覆盖自定义meta信息 x-bce-meta-foo3: 'bar3' // 覆盖自定义meta信息 } client.copyObject(<bucketName>, <key>, <targetBucketName>, <targetKey>, options);