有奖征文:轻量对象存储LighthouseCOS用户实践> HOT

下载与安装

相关资源

对象存储 COS 的 XML JS SDK 源码下载地址:XML JavaScript SDK
SDK 快速下载地址:XML JavaScript SDK
演示示例 Demo 下载地址:XML JavaScript SDK Demo
SDK 文档中的所有示例代码请参见 SDK 代码示例
SDK 更新日志请参见 ChangeLog
SDK 常见问题请参见:JavaScript SDK 常见问题
说明
如果您在使用 XML 版本 SDK 时遇到函数或方法不存在等错误,请先将 XML 版本 SDK 升级到最新版再重试。如果您仍在使用 JSON 版本 SDK,请 升级到 XML JavaScript SDK

准备环境

1. JavaScript SDK 需浏览器支持基本的 HTML5 特性(支持 IE10 以上浏览器),以便支持 ajax 上传文件和计算文件 MD5 值。
2. 登录 对象存储控制台创建存储桶。获取存储桶名称和 地域名称
3. 登录 访问管理控制台 ,获取您的项目 SecretId 和 SecretKey。
4. 配置 CORS 规则,AllowHeader 需配成*,ExposeHeaders 需要 ETag、Content-Length 以及其他 js 需要读取的 header 字段,如下图所示。操作详情请参见 设置跨域访问 文档。


说明
关于本文中出现的 SecretId、SecretKey、Bucket 等名称的含义和获取方式请参见 COS 术语信息
关于跨端框架(例如 uni-app)的使用说明,使用 JavaScript SDK 开发后无法打包成正常使用的移动应用,例如 Android App、iOS App,需要使用对应的 Android SDK、iOS SDK。
使用 Next.js、Nuxt.js 等服务端渲染技术时,请忽略警告“cos-js-sdk-v5 不支持 nodejs 环境使用,请改用 cos-nodejs-sdk-v5”,可正常使用JavaScript SDK。

安装 SDK

您可以通过以下方式安装 SDK:

script 引入

说明
建议将sdk下载到本地后引入,选择 地址一地址二 下载最新 cos-js-sdk-v5.min.js。
<!--src为本地路径 根据自己项目目录结构来调整-->
<script src="../dist/cos-js-sdk-v5.min.js"></script>
在 script 标签引用 SDK 时,SDK 占用了全局变量名 COS,通过它的构造函数可以创建 SDK 实例。

webpack 引入方式

通过 npm i cos-js-sdk-v5 --save 安装 SDK 依赖,支持 webpack 打包的场景,您可以用 npm 引入作为模块,代码如下:
const COS = require('cos-js-sdk-v5');

// 或

import COS from 'cos-js-sdk-v5';

开始使用

注意
建议用户 使用临时密钥 调用 SDK,通过临时授权的方式进一步提高 SDK 使用的安全性。申请临时密钥时,请遵循 最小权限指引原则,防止泄露目标存储桶或对象之外的资源。
如果您一定要使用永久密钥,建议遵循 最小权限指引原则 对永久密钥的权限范围进行限制。

获取临时密钥

由于固定密钥放在前端会有安全风险,正式部署时我们推荐使用临时密钥的方式,实现过程为:前端首先请求服务端,服务端使用固定密钥调用 STS 服务申请临时密钥(具体内容请参见 临时密钥生成和使用指引 文档),然后返回临时密钥到前端使用。
注意
如果站点有登录态,这个获取临时密钥接口,还需要加上登录态校验。

初始化

1. 创建 web.html,填入如下代码,并修改 web.html 中的存储桶名称和 Region。
2. 部署好后端的临时密钥服务,并修改 getAuthorization 里的密钥服务地址。
3. 把 web.html 放在 Web 服务器下,然后在浏览器访问页面,测试文件上传。web.html 文件示例代码如下:
<input id="file-selector" type="file">
<script src="dist/cos-js-sdk-v5.min.js"></script>
<script>

// 存储桶名称,由 bucketname-appid 组成,appid 必须填入,可以在 COS 控制台查看存储桶名称。 https://console.cloud.tencent.com/cos5/bucket
const Bucket = 'examplebucket-1250000000'; /* 存储桶,必须字段 */

// 存储桶 region 可以在 COS 控制台指定存储桶的概览页查看 https://console.cloud.tencent.com/cos5/bucket/
// 关于地域的详情见 https://cloud.tencent.com/document/product/436/6224
const Region = 'COS_REGION'; /* 存储桶所在地域,必须字段 */

// 初始化实例
const cos = new COS({
// getAuthorization 必选参数
getAuthorization: function (options, callback) {
// 初始化时不会调用,只有调用 cos 方法(例如 cos.putObject)时才会进入
// 异步获取临时密钥
// 服务端 JS 和 PHP 例子:https://github.com/tencentyun/cos-js-sdk-v5/blob/master/server/
// 服务端其他语言参考 COS STS SDK :https://github.com/tencentyun/qcloud-cos-sts-sdk
// STS 详细文档指引看:https://cloud.tencent.com/document/product/436/14048

const url = 'http://example.com/server/sts.php'; // url 替换成您自己的后端服务
const xhr = new XMLHttpRequest();
let data = null;
let credentials = null;
xhr.open('GET', url, true);
xhr.onload = function (e) {
try {
data = JSON.parse(e.target.responseText);
credentials = data.credentials;
} catch (e) {
}
if (!data || !credentials) {
return console.error('credentials invalid:\\n' + JSON.stringify(data, null, 2))
};
callback({
TmpSecretId: credentials.tmpSecretId,
TmpSecretKey: credentials.tmpSecretKey,
SecurityToken: credentials.sessionToken,
// 建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
StartTime: data.startTime, // 时间戳,单位秒,如:1580000000
ExpiredTime: data.expiredTime, // 时间戳,单位秒,如:1580000000
});
};
xhr.send();
}
});

// 接下来可以通过 cos 实例调用 COS 请求。

</script>

配置项

使用示例

创建一个 COS SDK 实例,COS SDK 支持以下格式创建:
格式一(推荐):后端通过获取临时密钥给到前端,前端计算签名。
const COS = require('cos-js-sdk-v5');
const cos = new COS({
// getAuthorization 必选参数
getAuthorization: function (options, callback) {
// 初始化时不会调用,只有调用 cos 方法(例如 cos.putObject)时才会进入
// 异步获取临时密钥
// 服务端 JS 和 PHP 例子:https://github.com/tencentyun/cos-js-sdk-v5/blob/master/server/
// 服务端其他语言参考 COS STS SDK :https://github.com/tencentyun/qcloud-cos-sts-sdk
// STS 详细文档指引看:https://cloud.tencent.com/document/product/436/14048

const url = 'http://example.com/server/sts.php'; // url 替换成您自己的后端服务
const xhr = new XMLHttpRequest();
let data = null;
let credentials = null;
xhr.open('GET', url, true);
xhr.onload = function (e) {
try {
data = JSON.parse(e.target.responseText);
credentials = data.credentials;
} catch (e) {
}
if (!data || !credentials) {
return console.error('credentials invalid:\\n' + JSON.stringify(data, null, 2))
};
callback({
TmpSecretId: credentials.tmpSecretId,
TmpSecretKey: credentials.tmpSecretKey,
SecurityToken: credentials.sessionToken,
// 建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
StartTime: data.startTime, // 时间戳,单位秒,如:1580000000
ExpiredTime: data.expiredTime, // 时间戳,单位秒,如:1580000000
});
};
xhr.send();
}
});
格式二(推荐):细粒度控制权限,后端通过获取临时密钥给到前端,只有在相同请求时,前端才重复使用临时密钥,后端可以通过 Scope 细粒度控制权限。
const COS = require('cos-js-sdk-v5');
const cos = new COS({
// getAuthorization 必选参数
getAuthorization: function (options, callback) {
// 初始化时不会调用,只有调用 cos 方法(例如 cos.putObject)时才会进入
// 服务端例子:https://github.com/tencentyun/qcloud-cos-sts-sdk/blob/master/scope.md
// 异步获取临时密钥
const url = 'http://example.com/server/sts.php'; // url 替换成您自己的后端服务
const xhr = new XMLHttpRequest();
let data = null;
let credentials = null;
xhr.open('POST', url, true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onload = function (e) {
try {
data = JSON.parse(e.target.responseText);
credentials = data.credentials;
} catch (e) {
}
if (!data || !credentials) {
return console.error('credentials invalid:\\n' + JSON.stringify(data, null, 2))
};
callback({
TmpSecretId: credentials.tmpSecretId,
TmpSecretKey: credentials.tmpSecretKey,
SecurityToken: credentials.sessionToken,
// 建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
StartTime: data.startTime, // 时间戳,单位秒,如:1580000000
ExpiredTime: data.expiredTime, // 时间戳,单位秒,如:1580000000
ScopeLimit: true, // 细粒度控制权限需要设为 true,会限制密钥只在相同请求时重复使用
});
};
xhr.send(JSON.stringify(options.Scope));
}
});
格式三(不推荐):前端每次请求前都需要通过 getAuthorization 获取签名,后端使用固定密钥或临时密钥计算签名返回至前端。该格式分块上传权限不便控制,不推荐您使用此格式。
const COS = require('cos-js-sdk-v5');
const cos = new COS({
// getAuthorization 必选参数
getAuthorization: function (options, callback) {
// 初始化时不会调用,只有调用 cos 方法(例如 cos.putObject)时才会进入
// 异步获取签名
const url = 'http://example.com/server/sts.php'; // url 替换成您自己的后端服务
const method = (options.Method || 'get').toLowerCase();
const query = options.Query || {};
const headers = options.Headers || {};
const pathname = options.Pathname || '/';
const xhr = new XMLHttpRequest();
const data = {
method: method,
pathname: pathname,
query: query,
headers: headers,
};
let res = null;
xhr.open('POST', url, true);
xhr.setRequestHeader('content-type', 'application/json');
xhr.onload = function (e) {
try {
res = JSON.parse(e.target.responseText);
} catch (e) {
}
if (!res || !res.authorization) return console.error('authorization invalid');
callback({
Authorization: res.authorization,
// SecurityToken: res.sessionToken, // 如果使用临时密钥,需要把 sessionToken 传给 SecurityToken
});
};
xhr.send(JSON.stringify(data));
},
});
格式四(不推荐):前端使用固定密钥计算签名,该格式适用于前端调试,若使用此格式,请避免泄露密钥。
var COS = require('cos-js-sdk-v5');

// SECRETID 和 SECRETKEY 请登录 https://console.cloud.tencent.com/cam/capi 进行查看和管理
var cos = new COS({
SecretId: 'SECRETID',
SecretKey: 'SECRETKEY',
});

new COS(options) 构造函数参数说明

参数名
参数描述
类型
是否必填
SecretId
用户的 SecretId
String
SecretKey
用户的 SecretKey,建议只在前端调试时使用,避免暴露密钥
String
FileParallelLimit
同一个实例下上传的文件并发数,默认值3
Number
ChunkParallelLimit
同一个上传文件的分块并发数,默认值3
Number
ChunkRetryTimes
分块上传及分块复制时,出错重试次数,默认值2(加第一次,请求共3次)
Number
ChunkSize
分块上传时,每片的字节数大小,默认值1048576(1MB)
Number
SliceSize
使用 uploadFiles 批量上传时,文件大小大于该数值将使用按分块上传,否则将调用简单上传,单位 Byte,默认值1048576(1MB)
Number
CopyChunkParallelLimit
进行分块复制操作中复制分块上传的并发数,默认值20
Number
CopyChunkSize
使用 sliceCopyFile 分块复制文件时,每片的大小字节数,默认值10485760(10MB)
Number
CopySliceSize
使用 sliceCopyFile 分块复制文件时,文件大小大于该数值将使用分块复制 ,否则将调用简单复制,默认值10485760(10MB)
Number
ProgressInterval
上传进度的回调方法 onProgress 的回调频率,单位 ms ,默认值1000
Number
Protocol
发请求时用的协议,可选项 https:http:,默认判断当前页面是 http: 时使用 http:,否则使用 https:
String
Domain
调用操作存储桶和对象的 API 时自定义请求域名。可以使用模板,如 "{Bucket}.cos.{Region}.myqcloud.com" ,即在调用 API 时会使用参数中传入的 Bucket 和 Region 进行替换。
String
UploadQueueSize
上传队列最长大小,超出的任务如果状态不是 waiting、checking、uploading 会被清理,默认10000
Number
UploadCheckContentMd5
上传文件时校验 Content-MD5,默认 false。如果开启,上传文件时会对文件内容计算 MD5,大文件耗时较长
Boolean
getAuthorization
获取签名的回调方法,如果没有 SecretId、SecretKey 时,这个参数必选
注意: 该回调方法在初始化实例时传入,在使用实例调用接口时才会执行并获取签名
Function
Timeout
超时时间,单位毫秒,默认为0,即不设置超时时间
Number
UseAccelerate
是否启用全球加速域名,默认为 false。若改为 true,需要存储桶开启全球加速功能,详情请参见 开启全球加速
Boolean

getAuthorization 回调函数说明(使用格式一)

getAuthorization: function(options, callback) { ... }
getAuthorization 的回调参数说明:
参数名
参数描述
类型
options
获取临时密钥需要的参数对象
Object
- Bucket
存储桶的名称,命名格式为 BucketName-APPID,此处填写的存储桶名称必须为此格式
String
- Region
存储桶所在地域,枚举值请参见 存储桶地域信息
String
callback
临时密钥获取完成后的回传方法
Function
获取完临时密钥后,callback 回传一个对象,回传对象的属性列表如下:
属性名
参数描述
类型
是否必填
TmpSecretId
获取回来的临时密钥的 tmpSecretId
String
TmpSecretKey
获取回来的临时密钥的 tmpSecretKey
String
SecurityToken
获取回来的临时密钥的 sessionToken,对应 header 的 x-cos-security-token 字段
String
StartTime
密钥获取的开始时间,即获取时刻的时间戳,单位秒,startTime,如:1580000000,用于签名开始时间,传入该参数可避免前端时间偏差签名过期问题
String
ExpiredTime
获取回来的临时密钥的 expiredTime,超时时刻的时间戳,单位秒,如:1580000900
String

getAuthorization 回调函数说明(使用格式二)

getAuthorization: function(options, callback) { ... }
getAuthorization 的函数说明回调参数说明:
参数名
参数描述
类型
options
获取签名需要的参数对象
Object
- Method
当前请求的 Method
String
- Pathname
请求路径,用于签名计算
String
- Key
对象键(Object 的名称),对象在存储桶中的唯一标识,了解更多可参见 对象概述
注意:当使用实例请求的接口不是对象操作相关接口时,该参数为空
String
- Query
当前请求的 query 参数对象,{key: 'val'} 的格式
Object
- Headers
当前请求的 header 参数对象,{key: 'val'} 的格式
Object
callback
临时密钥获取完成后的回调
Function
getAuthorization 计算完成后,callback 回传参数支持两种格式: 格式一:回传鉴权凭证字符串 Authorization。 格式二:回传一个对象,对象属性列表如下:
属性名
参数描述
类型
是否必填
Authorization
计算得到的签名字符串
String
SecurityToken
获取回来的临时密钥的 sessionToken,对应 header 的 x-cos-security-token 字段
String

获取鉴权凭证

实例本身鉴权凭证可以通过实例化时传入的参数控制如何或获取,有三种获取方式:
1. 实例化时,传入 SecretId、SecretKey,每次需要签名都由实例内部计算。
2. 实例化时,传入 getAuthorization 回调,每次需要签名通过这个回调计算完,返回签名至实例。
3. 实例化时,传入 getAuthorization 回调,调用回调时返回临时密钥凭证,在临时密钥凭证过期后会再次调用该回调。

开启 beacon 上报

为了持续跟踪和优化 SDK 的质量,给您带来更好的使用体验,我们在 SDK 中引入了 腾讯灯塔 SDK。
说明
腾讯灯塔只对 COS 侧的请求性能进行监控,不会上报业务侧数据。
若是想开启该功能,请先确保 SDK 版本升级到1.4.0及以上,然后在初始化中指定 EnableTracker 为 true。
new COS({
EnableTracker: true,
})

使用方式

回调方式

文档里默认使用回调方式,使用代码如下:
// 这里省略初始化过程和上传参数
const cos = new COS({ ... });
cos.uploadFile({ ... }, function(err, data) {
if (err) {
console.log('上传出错', err);
} else {
console.log('上传成功', data);
}
});

Promise

SDK 同样支持 Promise 方式调用,例如上述回调方式的代码等同于以下代码:
// 这里省略初始化过程和上传参数
const cos = new COS({ ... });
cos.uploadFile({ ... }).then(data => {
console.log('上传成功', data);
}).catch(err => {
console.log('上传出错', err);
});

同步方式

同步方式基于 JavaScript 的 async 和 await(使用时请注意浏览器兼容性),上述回调方式的代码等同于以下代码:
async function upload() {
// 这里省略初始化过程和上传参数
const cos = new COS({ ... });
try {
const data = await cos.uploadFile({ ... });
return { err: null, data: data }
} catch (err) {
return { err: err, data: null };
}
}
// 可以同步拿到请求的返回值,这里举例说明,实际返回的数据格式可以自定义
var uploadResult = await upload();
if (uploadResult.err) {
console.log('上传出错', uploadResult.err);
} else {
console.log('上传成功', uploadResult.data);
}
注意
cos.getObjectUrl 目前只支持回调方式。

使用技巧

通常情况下我们只需要创建一个 COS SDK 实例,然后在需要调用 SDK 方法的地方直接使用这个实例即可,示例代码如下:
/* vue 项目举例 */

/* 新建一个 cos.js,导出 cos 实例 */
import COS from 'cos-js-sdk-v5'; // 通过 npm 安装的 SDK
const cos = new COS({
....
});
export default cos;

/* 单页面里 page.vue */
<template>
<input id="fileSelector" type="file" @change="upload" />
</template>
<script>
/* 引入上方新建的 cos.js路径 */
import cos from 'cos';
export default {
data() {},
methods: {
upload(e) {
const file = e.target.files && e.target.files[0];
/* 直接调用 cos sdk 的方法 */
cos.uploadFile({
Bucket: 'examplebucket-1250000000', /* 填写自己的 bucket,必须字段 */
Region: 'COS_REGION', /* 存储桶所在地域,必须字段 */
Key: '1.jpg', /* 存储在桶里的对象键(例如1.jpg,a/b/test.txt),必须字段 */
Body: file, // 上传文件对象
SliceSize: 1024 * 1024 * 5, /* 触发分块上传的阈值,超过5MB 使用分块上传,小于5MB使用简单上传。可自行设置,非必须 */
});
}
},
}
</script>

常见接口

以下是部分常用接口例子,更详细的初始化方法请参见 demo 示例。

查询对象列表

cos.getBucket({
Bucket: 'examplebucket-1250000000', /* 填写自己的 bucket,必须字段 */
Region: 'COS_REGION', /* 存储桶所在地域,必须字段 */
Prefix: 'a/', /* 列出目录 a 下所有文件,非必须 */
}, function(err, data) {
console.log(err || data.Contents);
});

上传对象

强烈推荐使用高级上传接口 uploadFile,自动针对小文件使用简单上传,大文件使用分块上传,性能更好。详情请参见 高级上传 文档。 若使用临时密钥方式,需同时授权简单上传对象分块上传的权限。请参考授权指引。 常见上传错误排查,请参考 常见问题
<!-- html 页面 DOM 元素 -->

<!-- 选择要上传的文件 -->
<input id="fileSelector" type="file" />
<!-- 点击按钮上传 -->
<input id="submitBtn" type="submit" />
function handleFileInUploading(file) {
cos.uploadFile({
Bucket: 'examplebucket-1250000000', /* 填写自己的 bucket,必须字段 */
Region: 'COS_REGION', /* 存储桶所在地域,必须字段 */
Key: '1.jpg', /* 存储在桶里的对象键(例如:1.jpg,a/b/test.txt,图片.jpg)支持中文,必须字段 */
Body: file, // 上传文件对象
SliceSize: 1024 * 1024 * 5, /* 触发分块上传的阈值,超过5MB使用分块上传,小于5MB使用简单上传。可自行设置,非必须 */
onProgress: function(progressData) {
console.log(JSON.stringify(progressData));
}
}, function(err, data) {
if (err) {
console.log('上传失败', err);
} else {
console.log('上传成功');
}
});
}

/* 选择文件 */
document.getElementById('submitBtn').onclick = function (e) {
const file = document.getElementById('fileSelector').files[0];
if (!file) {
document.getElementById('msg').innerText = '未选择上传文件';
return;
}
handleFileInUploading(file);
};


下载对象

注意:
浏览器里通过生成预签名 url 并触发浏览器下载的方式实现。
cos.getObjectUrl({
Bucket: 'examplebucket-1250000000', /* 填写自己的 bucket,必须字段 */
Region: 'COS_REGION', /* 存储桶所在地域,必须字段 */
Key: '1.jpg', /* 存储在桶里的对象键(例如1.jpg,a/b/test.txt),必须字段 */
}, function(err, data) {
if (err) return console.log(err);
/* 通过指定 response-content-disposition=attachment 实现强制下载 */
const downloadUrl = data.Url + (data.Url.indexOf('?') > -1 ? '&' : '?') + 'response-content-disposition=attachment';
/* 可拼接 filename 来实现下载时重命名 */
/* downloadUrl += ';filename=myname'; */
// (推荐使用 window.open()方式)这里是新窗口打开 url,如果需要在当前窗口打开,可以使用隐藏的 iframe 下载,或使用 a 标签 download 属性协助下载
window.open(downloadUrl);
});

删除对象

cos.deleteObject({
Bucket: 'examplebucket-1250000000', /* 填写自己的 bucket,必须字段 */
Region: 'COS_REGION', /* 存储桶所在地域,必须字段 */
Key: '1.jpg', /* 存储在桶里的对象键(例如1.jpg,a/b/test.txt),必须字段 */
}, function(err, data) {
console.log(err || data);
});