OSS 前端自动化部署:

使用 node.js 或 python。

阿里云官方文档(使用 nodejs)

快速入门

OSS(options)中的各个配置项说明如下:

  • [accessKeyId] {String}:通过阿里云控制台创建的AccessKey。
  • [accessKeySecret] {String}:通过阿里云控制台创建的AccessSecret。
  • [stsToken] {String}:使用临时授权方式,详情请参见使用 STS 进行临时授权。
  • [bucket] {String}:通过控制台或PutBucket创建的bucket。
  • [endpoint] {String}:OSS域名。
  • [region] {String}:bucket所在的区域, 默认oss-cn-hangzhou。
  • [internal] {Boolean}:是否使用阿里云内网访问,默认false。比如通过ECS访问OSS,则设置为true,采用internal的endpoint可节约费用。
  • [cname] {Boolean}:是否支持上传自定义域名,默认false。如果cname为true,endpoint传入自定义域名时,自定义域名需要先同bucket进行绑定。
  • [isRequestPay] {Boolean}:bucket是否开启请求者付费模式,默认false。具体可查看请求者付费模式。
  • [secure] {Boolean}:(secure: true)则使用HTTPS,(secure: false)则使用HTTP,详情请查看常见问题。
  • [timeout] {String|Number}:超时时间,默认60s。

安装 ali-oss

1
npm install ali-oss

OSS NodeJS SDK同时支持同步和异步的使用方式

region是指您申请 OSS 服务时的区域,例如oss-cn-hangzhou。完整的区域列表请参考访问域名和数据中心

同步方式:基于async和await方式,异步编程同步化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
let OSS = require('ali-oss');

let client = new OSS({
region: '<oss region>',
//云账号AccessKey有所有API访问权限,建议遵循阿里云安全最佳实践,部署在服务端使用RAM子账号或STS,部署在客户端使用STS。
accessKeyId: '<Your accessKeyId>',
accessKeySecret: '<Your accessKeySecret>',
bucket: '<Your bucket name>'
});

async function put () {
try {
// object表示上传到OSS的Object名称,localfile表示本地文件或者文件路径
let r1 = await client.put('object','localfile');
console.log('put success: %j', r1);
let r2 = await client.get('object');
console.log('get success: %j', r2);
} catch(e) {
console.error('error: %j', err);
}
}
put();

异步方式:类似callback的方式,API接口返回Promise,使用.then()处理返回结果,使用.catch()处理错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let OSS = require('ali-oss');

let client = new OSS({
region: '<oss region>',
//云账号AccessKey有所有API访问权限,建议遵循阿里云安全最佳实践,部署在服务端使用RAM子账号或STS,部署在客户端使用STS。
accessKeyId: '<Your accessKeyId>',
accessKeySecret: '<Your accessKeySecret>',
bucket: '<Your bucket name>'
});

// object表示上传到OSS的Object名称,localfile表示本地文件或者文件路径
client.put('object', 'localfile').then(function (r1) {
console.log('put success: %j', r1);
return client.get('object');
}).then(function (r2) {
console.log('get success: %j', r2);
}).catch(function (err) {
console.error('error: %j', err);
});

子账号访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
let OSS = require('ali-oss');
let STS = OSS.STS;
let sts = new STS({
accessKeyId: '<子账号的AccessKeyId>',
accessKeySecret: '<子账号的AccessKeySecret>'
});
async function assumeRole () {
try {
let token = await sts.assumeRole(
'<role-arn>', '<policy>', '<expiration>', '<session-name>');
let client = new OSS({
region: '<region>',
accessKeyId: token.credentials.AccessKeyId,
accessKeySecret: token.credentials.AccessKeySecret,
stsToken: token.credentials.SecurityToken,
bucket: '<bucket-name>'
});
} catch (e) {
console.log(e);
}
}
assumeRole();

STS 临时授权访问 OSS 步骤

查看存储空间(Bucket)列表(node app.js 运行)

1
2
3
4
5
6
7
8
9
async function listBuckets () {
try {
let result = await client.listBuckets();
} catch(err) {
console.log(err)
}
}

listBuckets();

查看文件列表

1
2
3
4
5
6
7
8
9
10
11
12
client.useBucket('Your bucket name');
async function list () {
try {
let result = await client.list({
'max-keys': 5
})
console.log(result)
} catch (err) {
console.log (err)
}
}
list();

上传文件

1
2
3
4
5
6
7
8
9
10
11
12
client.useBucket('Your bucket name');

async function put () {
try {
let result = await client.put('object-name', 'local file');
console.log(result);
} catch (err) {
console.log (err);
}
}

put();

下载文件

1
2
3
4
5
6
7
8
9
10
async function get () {
try {
let result = await client.get('object-name');
console.log(result);
} catch (err) {
console.log (err);
}
}

get();

删除文件

1
2
3
4
5
6
7
8
9
10
async function delete () {
try {
let result = await client.delete('object-name');
console.log(result);
} catch (err) {
console.log (err);
}
}

delete();

完整流程

存储空间

创建 Bucket

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let OSS = require('ali-oss');

let client = new OSS({
region: '<Your region>',
accessKeyId: '<Your AccessKeyId>',
accessKeySecret: '<Your AccessKeySecret>'
});

// putBucket
async function putBucket() {
try {
const result = await client.putBucket('your bucket name');
console.log(result);
} catch (err) {
console.log(err);
}
}

putBucket();

删除 Bucket

  • 如果该 Bucket 下还有文件,则需要先删除所有文件才能删除 Bucket。
  • 如果该 Bucket 下还有未完成的上传请求,则需要通过listUploads和abortMultipartUpload取消请求后才能删除 Bucket。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let OSS = require('ali-oss');

let client = new OSS({
region: '<Your region>',
accessKeyId: '<Your AccessKeyId>',
accessKeySecret: '<Your AccessKeySecret>'
});

async function deleteBucket() {
try {
const result = await client.deleteBucket('your bucket name');
console.log(result);
} catch (err) {
console.log(err);
}
}

deleteBucket();

设置访问权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let OSS = require('ali-oss');

let client = new OSS({
region: '<Your region>',
accessKeyId: '<Your AccessKeyId>',
accessKeySecret: '<Your AccessKeySecret>'
});

async function putBucketACL() {
try {
const result = await client.putBucketACL('bucket name', 'public-read');
console.log(result);
} catch (err) {
console.log(err);
}
}

putBucketACL();

上传文件

上传本地文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let OSS = require('ali-oss')

let client = new OSS({
region: '<Your region>',
accessKeyId: '<Your AccessKeyId>',
accessKeySecret: '<Your AccessKeySecret>',
bucket: '<Your bucket name>',
});

async function put () {
try {
let result = await client.put('object-name', 'local-file');
console.log(result);
} catch (e) {
console.log(e);
}
}

put();

流式上传

当使用 putStream 接口时,SDK 默认会发起一个 chunked encoding 的 HTTP PUT 请求。如果在 options 指定了 contentLength 参数,则不会使用 chunked encoding。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
let OSS = require('ali-oss');
let fs = require('fs');

let client = new OSS({
region: '<Your region>',
accessKeyId: '<Your AccessKeyId>',
accessKeySecret: '<Your AccessKeySecret>',
bucket: '<Your bucket name>'
});

async function putStream () {
try {
// use 'chunked encoding'
let stream = fs.createReadStream('local-file');
let result = await client.putStream('object-name', stream);
console.log(result);

// don't use 'chunked encoding'
let stream = fs.createReadStream('local-file');
let size = fs.statSync('local-file').size;
let result = await client.putStream(
'object-name', stream, {contentLength: size});
console.log(result);
} catch (e) {
console.log(e)
}
}

putStream();

管理文件

判断文件是否存在

1
2
3
4
5
6
7
8
9
client.get(object).then((result) => {
if (result.res.status == 200) {
return true
}
}).catch((e)=> {
if (e.code == 'NoSuchKey') {
return false
}
})

列举指定Bucket下的所有文件

  • prefix:只列出符合特定前缀的文件。
  • marker:只列出文件名大于 marker 之后的文件。
  • delimiter:用于获取文件的公共前缀。
  • max-keys:用于指定最多返回的文件个数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
let OSS = require('ali-oss');
let client = new OSS({
region: '<Your region>',
accessKeyId: '<Your AccessKeyId>',
accessKeySecret: '<Your AccessKeySecret>',
bucket: '<Your bucket name>'
});
async function list () {
{
// 不带任何参数,默认最多返回1000个文件。
let result = await client.list();
console.log(result);
// 根据nextMarker继续列出文件。
if (result.isTruncated) {
let result = await client.list({
marker: result.nextMarker
});
}
// 列举前缀为'my-'的文件。
let result = await client.list({
prefix: 'my-'
});
console.log(result);
// 列举前缀为'my-'且在'my-object'之后的文件。
let result = await client.list({
prefix: 'my-',
marker: 'my-object'
});
console.log(result);
} catch (e) {
console.log(e);
}
}
list();

删除文件

删除单个文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let OSS = require('ali-oss')

let client = new OSS({
region: '<Your region>',
accessKeyId: '<Your AccessKeyId>',
accessKeySecret: '<Your AccessKeySecret>',
bucket: '<Your bucket name>',
});

async function delete () {
try {
let result = await client.delete('object-name');
console.log(result);
} catch (e) {
console.log(e);
}
}

delete();
删除多个文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
let OSS = require('ali-oss')

let client = new OSS({
region: '<Your region>',
accessKeyId: '<Your AccessKeyId>',
accessKeySecret: '<Your AccessKeySecret>',
bucket: '<Your bucket name>',
});

async function deleteMulti () {
try {
let result = await client.deleteMulti(['obj-1', 'obj-2', 'obj-3']);
console.log(result);
let result = await client.deleteMulti(['obj-1', 'obj-2', 'obj-3'], {
quiet: true
});
console.log(result);
} catch (e) {
console.log(e);
}
}

deleteMulti();

访问日志

开启访问日志记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let OSS = require('ali-oss')
let client = new OSS({
region: '<Your region>'
accessKeyId: '<Your AccessKeyId>',
accessKeySecret: '<Your AccessKeySecret>',
bucket: '<Your bucket name>'
});
async function putBucketLogging () {
try {
let result = await client.putBucketLogging('bucket-name', 'logs/');
console.log(result)
} catch (e) {
console.log(e)
}
}
putBucketLogging();

查看访问日志设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let OSS = require('ali-oss')

let client = new OSS({
region: '<Your region>'
accessKeyId: '<Your AccessKeyId>',
accessKeySecret: '<Your AccessKeySecret>',
bucket: '<Your bucket name>'
});

async function getBucketLogging() {
try {
let result = await client.getBucketLogging('bucket-name');
console.log(result);
} catch (e) {
console.log(e);
}
})

getBucketLogging();

关闭访问日志记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let OSS = require('ali-oss')

let client = new OSS({
region: '<Your region>'
accessKeyId: '<Your AccessKeyId>',
accessKeySecret: '<Your AccessKeySecret>',
bucket: '<Your bucket name>'
});

async function deleteBucketLogging () {
try {
let result = await client.deleteBucketLogging('bucket-name');
console.log(result);
} catch (e) {
console.log(e);
}

deleteBucketLogging();

静态网站托管

设置静态网站托管

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
let OSS = require('ali-oss')

let client = new OSS({
region: '<Your region>'
accessKeyId: '<Your AccessKeyId>',
accessKeySecret: '<Your AccessKeySecret>',
bucket: '<Your bucket name>'
});

async function putBucketWebsite () {
try {
let result = await client.putBucketWebsite('bucket-name', {
index: 'index.html',
error: 'error.html'
});
console.log(result);
} catch (e) {
console.log(e);
}
}

putBucketWebsite();

查看静态网站托管配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let OSS = require('ali-oss')

let client = new OSS({
region: '<Your region>'
accessKeyId: '<Your AccessKeyId>',
accessKeySecret: '<Your AccessKeySecret>',
bucket: '<Your bucket name>'
});

async function getBucketWebsite () {
try {
let result = await client.getBucketWebsite('bucket-name');
console.log(result);
} catch (e) {
console.log(e);
}
}

getBucketWebsite();

删除静态网站托管配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let OSS = require('ali-oss')

let client = new OSS({
region: '<Your region>'
accessKeyId: '<Your AccessKeyId>',
accessKeySecret: '<Your AccessKeySecret>',
bucket: '<Your bucket name>'
});

async function deleteBucketWebsite() {
try {
let result = await client.deleteBucketWebsite('bucket-name');
console.log(result);
} catch (e) {
console.log(e);
}
}

deleteBucketWebsite();

最终代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
const fs = require('fs');
const join = require('path').join;

let OSS = require('ali-oss');
let STS = OSS.STS;
let sts = new STS({
accessKeyId: 'LTA&*******5p',
accessKeySecret: 'VNbvLHs**********j2vPsK'
});

const BucketName = 'demo-demo-demo';
const Region = 'oss-cn-shanghai***';
const Ram = 'acs:ram::185190330623****:role/aliyunoss***';
const BaseDir = 'dist';

sts.assumeRole(Ram).then((token) => {
return new OSS({
region: Region,
accessKeyId: token.credentials.AccessKeyId,
accessKeySecret: token.credentials.AccessKeySecret,
stsToken: token.credentials.SecurityToken
});
}).then((client) => {
client.listBuckets().then((buckets) => {
let flag = false;
if (buckets.buckets) {
for (let i = 0, j = buckets.buckets.length; i < j; i++) {
if (buckets.buckets[i].name === BucketName) {
flag = true;
}
}
}
if (flag) {
client.putBucketACL(BucketName, 'public-read').then(() => {
client.putBucketWebsite(BucketName, {index: 'index.html'});
client.useBucket(BucketName);
client.list().then((res) => {
if (res.objects && res.objects.length > 0) {
for (let i = 0, j = res.objects.length; i < j; i++) {
client.delete(res.objects[i].name)
}
}
}).then(() => {
function getJsonFiles(jsonPath) {
let jsonFiles = [];

function findJsonFile(path) {
let files = fs.readdirSync(path);
files.forEach(function (item, index) {
let fPath = join(path, item);
let stat = fs.statSync(fPath);
if (stat.isDirectory() === true) {
findJsonFile(fPath);
}
if (stat.isFile() === true) {
jsonFiles.push(fPath);
}
});
}

findJsonFile(jsonPath);
return jsonFiles;
}

let filesArr = getJsonFiles("./" + BaseDir);
for (let i = 0, j = filesArr.length; i < j; i++) {
client.put(filesArr[i].replace('dist/', ''), filesArr[i]).catch((err) => {
console.log('errors:-------\n' + err);
});
}
});
});
} else {
client.putBucket(BucketName).then(() => {
client.putBucketACL(BucketName, 'public-read').then(() => {
client.putBucketWebsite(BucketName, {index: 'index.html'});
client.useBucket(BucketName);

function getJsonFiles(jsonPath) {
let jsonFiles = [];

function findJsonFile(path) {
let files = fs.readdirSync(path);
files.forEach(function (item, index) {
let fPath = join(path, item);
let stat = fs.statSync(fPath);
if (stat.isDirectory() === true) {
findJsonFile(fPath);
}
if (stat.isFile() === true) {
jsonFiles.push(fPath);
}
});
}

findJsonFile(jsonPath);
return jsonFiles;
}

let filesArr = getJsonFiles("./" + BaseDir);
for (let i = 0, j = filesArr.length; i < j; i++) {
client.put(filesArr[i].replace('dist/', ''), filesArr[i]).catch((err) => {
console.log('errors:-------\n' + err);
});
}
});
})
}
});
}).catch((res) => {
console.log(res);
});

注意事项

  • 子账号通过 sdk 访问阿里云 OSS 需要相关的权限配置,具体流程可见官网文档描述
  • 域名绑定,需要 CDN 权限
  • 结合 vue 脚手架工具打包工程+上传到 OSS,先按照 ali-oss,然后如上在根目录创建 app.js 后,在 packsge.json 中加入脚本:
    1
    "oss": "vue-cli-service build && echo \"uploading...\nPlease wait for a while...\" && node app.js && echo \"success\""
  • 参数说明
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // STS 访问需要的子用户 accessKeyId 和 accessKeySecret
    let sts = new STS({
    accessKeyId: 'LTAI****do5p',
    accessKeySecret: 'VNbv****vPsK'
    });
    // 本地要上传的文件夹名称(默认 dist)
    const BaseDir = 'dist';
    // OSS 存储的名称
    const BucketName = 'demo-demo-demo';
    // OSS 存储的区域
    const Region = 'oss-cn-shanghai';
    // 通过 STS 临时访问需要的 ram
    const Ram = 'acs:ram::1851****3203:role/aliyunoss****';