使用指南
云开发 2.0 PaaS 自定义模式 提供了底层资源无关的云存储、云数据库、云函数调用能力和通用 HTTP 服务转发功能,借助它,云开发可以与自有 IaaS 配合使用,满足更丰富的定制化场景。本指南将提供上手云函数、HTTP 服务转发、云数据库 CRUD 和 云存储文件访问 的基础指引。
准备工作
要使用云开发自定义模式,需要先在腾讯云控制台开通自定义模式环境,并连接需要使用的资源(云数据库、云函数、服务提供方等)。
注意:自定义模式集成了云开发 IDaaS 登录体系,需要完成登录(即拥有登录态的用户)才能调用服务,所以需要配合云开发 IDaaS 能力使用。
这需要从 云开发 IDaaS 身份认证服务获取用于调用 OpenAPI 的 AccessToken
,并在调用时通过请求头 Authorization
发送。
以下为通过 js-sdk
的方式,完成登录流程,并在请求时,自动携带登录相关信息。
import { CloudbaseOAuth } from "@cloudbase/oauth";
import * as tcbpaas from "@cloudbase/paas-js-sdk";
// 初始化 CloudbaseOAuth 实例
const oauth = new CloudbaseOAuth({
apiOrigin: "https://{env}.ap-shanghai.auth.tcloudbase.com",
clientId: "your-client-id", // 通过控制台获取
});
// 初始化 tcbpaas sdk 实例
tcbpaas.init({
env: "your-env-id",
baseURL: "https://{env}.ap-shanghai.api.tcloudbase.com",
oauthInstance: oauth,
});
// 按需进行匿名登录
async function signInAnonymously() {
const result = await oauth.authApi.hasLoginStateSync();
if (!result) {
await oauth.authApi.signInAnonymously();
}
}
signInAnonymously();
async function r(options) {
await signInAnonymously();
// 调用API
return tcbpaas.request(options);
}
本指南后续将使用更通用的 curl
或 Node.js
进行 API 调用演示。
服务提供方
服务提供方可选云函数(SCF)和自定义 HTTP 服务,其调用地址均为:
https://{env}.ap-shanghai.gateway.tcloudbase.com/
其中 env
为云开发 PaaS 环境 ID,可以在云开发控制台进行查看。
调用云函数 SCF
在调用云函数之前,需要先在控制台绑定对应的云函数命名空间,绑定的命名空间下所有云函数即可被调用。例如:
云函数可以在Serverless 函数服务控制台进行创建与更新。
以下是一个简单的云函数 echo
,它将返回请求的触发事件数据 event
:
exports.main_handler = async (event, context) => {
return event;
};
调用该云函数,需在请求 Query
参数 fn
指定要访问的函数名称。
使用 curl
调用:
curl -X POST \
-H "Authorization: Bearer {{accesstoken}}" \
-H "Content-Type: application/json" \
-H "X-RequestId: 783c4a34-73d4-11ed-b363-38f3ab16981b" \
-d '{ "key": "value" }' \
"https://{env}.ap-shanghai.gateway.tcloudbase.com/path/to/target?fn=echo&k=v"
云函数接收到的事件触发信息 event
内容如下:
{
// body 请求体,对应 http 请求 body
"body": {
"key": "value"
},
// header 请求头,对应 http 请求 header
"header": {
"Accept": ["*/*"],
"Authorization": ["Bearer {{accesstoken}}"],
"Content-Length": ["22"],
"Content-Type": ["application/json"],
"Traceparent": [
// 用于 http trace 的 header
"00-81d2afea14efe195a4aa8d12ebb30fa7-f2a8bb8bc673a1f1-01"
],
"Tracestate": [
// 用于 http trace 的 header
"tcb-paas-openapi=tracer"
],
"User-Agent": ["curl/7.68.0"]
},
"method": "POST",
"path": "/path/to/target",
"query": "fn=echo&k=v",
// 请求Id
"requestId": "783c4a34-73d4-11ed-b363-38f3ab16981b",
// tcb 请求上下文
"tcbContext": {
"accessToken": "Bearer {{accesstoken}}",
"appId": "1********", // 腾讯云账号AppId
"envId": "{{env}}", // PaaS 环境 ID
"uin": "100*******", // 腾讯云账号Uin
"userId": "1*****",
"userScope": ""
}
}
调用时的请求体会被置于 body
中。
上面的请求指定了 Content-Type: application/json
,如果不指定该字段,云函数收到的 event
将会是:
{
"body": "{ \"key\": \"value\" }"
}
指定 Content-Type
内容类型为 application/json
或 application/ld+json
时,服务端会将解析后的 JSON 放到 event
的 body
字段上。
此外,如果传递了不合法的 JSON 格式数据,即使声明了 Content-Type: application/json
,云函数也将接收到未解析的 JSON。例如如下调用:
curl -X POST \
-H "Authorization: {{accesstoken}}" \
-H "Content-Type: application/json" \
-d '{ "key": "value }' \
"https://{env}.ap-shanghai.gateway.tcloudbase.com?fn=echo"
云函数接收到的 body
内容为:
{
"body": "{ \"key\": \"value }"
}
实例:利用云函数压缩 JPG 图片
这个例子将提供一个更真实的案例:通过云开发 PaaS OpenAPI 调用提供了压缩图片功能的云函数,并得到压缩后的图片。
首先是云函数部分。在这个名为compress
的云函数中,实现对 JPG 图片进行压缩的功能:
云函数代码:
// 云函数入口文件 index.js
const images = require("images");
exports.main_handler = async (event, context) => {
// 从请求体中读取 base64 格式的图片
const imageBuf = event["body"] && Buffer.from(event["body"], "base64");
let result = {
message: "image not found",
code: "NOT_FOUND",
};
if (imageBuf) {
const originalSize = imageBuf.length;
const start = Date.now();
const compressedBuf = compress(imageBuf);
const timeCost = Date.now() - start;
const compressSize = compressedBuf.length;
const ratio = (compressSize / originalSize) * 100;
// 对图片进行压缩,并返回压缩后的图片、压缩时间和压缩比率
result = {
...result,
message: "compress success",
code: "SUCCESS",
compressedBuf,
ratio,
timeCost,
};
}
return result;
};
function compress(imageBuf) {
return images(imageBuf).encode("jpg", { quality: 20 });
}
客户端请求代码:
// 调用 PaaS OpenAPI 的参数:
const fnName = "compress";
const envId = "{{env}}";
const host = `${envId}.ap-shanghai.gateway.tcloudbase.com`;
const authorization = "Bearer {{accesstoken}}";
const url = `https://${host}/path/to/target?fn=${fnName}`;
// 获取一张随机图片,并将之转码为 `base64` 格式:
const resp = await fetch("https://picsum.photos/200", { method: "GET" });
const imageBuf = await resp.arrayBuffer();
const image = Buffer.from(imageBuf).toString("base64");
// 调用 OpenAPI 得到压缩后的图片,并将之写入本地文件:
fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Host": host,
Authorization: authorization,
},
body: image,
})
.then((res) => res.json())
.then((res) => {
// 打印返回结果
console.log(res);
// 将图片保存至本地
const data = Buffer.from(res.compressedBuf, "base64");
fs.writeFileSync("compressed.jpg", data);
});
调用成功的返回结果如下:
{
"code": "SUCCESS",
"compressedBuf": {
"data": [
255, 216, 255, 224, 0, 16, 74, 70, 73, 70, 0, 1 ...
],
"type": "Buffer"
},
"message": "compress success",
"ratio": 44.78914202617547,
"timeCost": 2
}
并能可以在本地看到压缩后的随机图片。
调用 HTTP 服务
在调用 HTTP 服务之前,需要先在控制台配置 HTTP 服务的转发地址,例如:
如图将服务地址转发至
https://httpbin.org
,这是一个用于获取各类 HTTP 响应的服务,后面将使用它来获取一段 HTTP JSON 响应。
与调用云函数类似,Authorization
请求头是必要的,另外,调用的路径应被拼接在请求路径之后。
例如,此处需要调用 https://httpbin.org/json
,需要把 /json
拼接在原有的调用路径之后。
注意:HTTP 服务提供方仅支持 VPC内网服务
curl -H "Authorization: {{accesstoken}}" \
-H "Content-Type: application/json" \
"https://{env}.ap-shanghai.gateway.tcloudbase.com/json"
将会返回如下结果:
{
"slideshow": {
"author": "Yours Truly",
"date": "date of publication",
"slides": [
{
"title": "Wake up to WonderWidgets!",
"type": "all"
},
{
"items": [
"Why <em>WonderWidgets</em> are great",
"Who <em>buys</em> WonderWidgets"
],
"title": "Overview",
"type": "all"
}
],
"title": "Sample Slide Show"
}
}
云数据库
在调用云数据库 API 之前,需要先在控制台绑定对应云数据库(当前仅支持腾讯云 MongoDB)。
通过调用 PaaS OpenAPI,可以对多文档或单文档进行查询、插入、更新、删除、聚合、计数等操作,对于每一个集合,都可以在控制台「集合配置」界面设置不同的读写策略来保证数据安全。
在执行每种操作时,可以通过 Query
参数 mode
指定使用 JSON
、ExtJSON
格式操作文档。
本指南不会涉及有关 MongoDB
的基础概念和详细的 API 说明,仅采用 mode=JSON
格式数据进行 API 调用演示,有关具体 API 定义,请参考API 文档。
数据库的调用地址格式为:
https://{env}.ap-shanghai.api.tcloudbase.com/v1/databases/-/collections/{collectionName}/{operate}?mode=JSON
其中:
env
为云开发 PaaS 环境 ID,可以在云开发控制台进行查看。collectionName
为需要操作的数据库集合名。operate
为对应的操作mode
为文档数据格式,JSON
|ExtJSON
插入文档 Insert
POST https://{env}.ap-shanghai.api.tcloudbase.com/v1/databases/-/collections/{collectionName}/insert?mode=JSON
在请求体的 docs
参数中填写需要插入的文档:
curl -X POST \
-H "Authorization: Bearer {{accesstoken}}" \
-H "Content-Type: application/json" \
-d '{ "docs": [{"id": 1, "a": 1}, {"id": 2, "a": 2}] }' \
"https://{env}.ap-shanghai.api.tcloudbase.com/v1/databases/-/collections/{collectionName}/insert?mode=JSON"
该请求插入了如下的两条文档:
返回值指示了插入文档的数量及 ID
:
{
"inserted": 2,
"insertedIds": [
"09a2b1ab638d9fb90000006b5bd0a3f1",
"09a2b1ab638d9fb90000006c4ce1a2bc"
]
}
查询文档 Query
POST https://{env}.ap-shanghai.api.tcloudbase.com/v1/databases/-/collections/{collectionName}/query?mode=JSON
在请求体的 query
参数中填写查询条件,其他可指定的参数有:
projection
: 返回字段,1
表示返回,-1
表示不返回,如:a:1,b:1,c.d.e:1,_id:-1
,则返回a
、b
、c.d.e
sort
: 排序字段,1
表示正序,-1
表示倒序,排序字段顺序决定排序次序,如:sales:1
,则按sales
正序排序offset
: 偏移量limit
: 限制数量
curl -X POST \
-H "Authorization: Bearer {{accesstoken}}" \
-H "Content-Type: application/json" \
-d '{ "query": {"id": 1} }' \
"https://{env}.ap-shanghai.api.tcloudbase.com/v1/databases/-/collections/{collectionName}/query?mode=JSON"
该请求查询 id=1
的文档,返回值如下所示:
{
"offset": 0,
"limit": 0,
"docs": [
{
"_id": "09a2b1ab638d9fb90000006b5bd0a3f1",
"_openid": "1563083521218580480",
"a": 1,
"id": 1
}
]
}
返回值包含了查询所得的文档列表 docs
、请求传入的 offset
和 limit
。
更新文档 Update
POST https://{env}.ap-shanghai.api.tcloudbase.com/v1/databases/-/collections/{collectionName}/update?mode=JSON
在请求体的 query
参数中填写查询条件,update
中填写更新规则,其他可指定字段有:
upsert
:boolean
无匹配文档时是否插入文档,默认false
multi
:boolean
是否更新多条数据,默认false
isReturnNewDoc
:boolean
是否返回更新后的文档,默认false
注意,isReturnNewDoc
和 multi
不能同时为 true
,isReturnNewDoc
和 upsert
也不能同时为 true
。
curl -X POST \
-H "Authorization: Bearer {{accesstoken}}" \
-H "Content-Type: application/json" \
-d '{ "query": {"id": 1}, "update": {"$set": { "a": 100 }} }' \
"https://{env}.ap-shanghai.api.tcloudbase.com/v1/databases/-/collections/{collectionName}/update?mode=JSON"
该请求将 id=1
的文档的 a
字段修改为 100。返回值如下:
{
"matched": 1, // 匹配的文档数量
"modified": 1, // 更新的文档数据
"upsertId": "", // 更新的文档 Id
"newDoc": "" // 如果 isReturnNewDoc=true ,则该字段返回更新后的文档
}
文档计数 Count
POST https://{env}.ap-shanghai.api.tcloudbase.com/v1/databases/-/collections/{collectionName}/count?mode=JSON
在请求体的 query
参数中填写查询条件。
curl -X POST \
-H "Authorization: Bearer {{accesstoken}}" \
-H "Content-Type: application/json" \
-d '{ "query": {"a": {"$gt": 50}} }' \
"https://{env}.ap-shanghai.api.tcloudbase.com/v1/databases/-/collections/{collectionName}/count?mode=JSON"
该请求查询字段 a>50
的文档数量,返回值指示了符合条件的查询结果:
{
"count": 1
}
查询条件中的
$gt
为 MongoDB 操作符。
聚合文档 Aggregate
POST https://{env}.ap-shanghai.api.tcloudbase.com/v1/databases/-/collections/{collectionName}/aggregate?mode=JSON
在请求体的pipeline
参数中填写聚合管道。
curl -X POST \
-H "Authorization: Bearer {{accesstoken}}" \
-H "Content-Type: application/json" \
-d '{"pipeline":[{"$match":{"a": 100}},{"$group":{"_id":"a"}}]}' \
"https://{env}.ap-shanghai.api.tcloudbase.com/v1/databases/-/collections/{collectionName}/aggregate?mode=JSON"
该请求选出所有 a=100
的文档并按 a
分组。返回值示意:
{ "results": [{ "_id": "a" }] }
删除文档 Delete
POST https://{env}.ap-shanghai.api.tcloudbase.com/v1/databases/-/collections/{collectionName}/delete?mode=JSON
在请求体的 query
参数中填写查询条件,使用 multi
指定是否更新多条数据,默认为 false
。
curl -X POST \
-H "Authorization: Bearer {{accesstoken}}" \
-H "Content-Type: application/json" \
-d '{ "query": {"a": {"$gt": 50}} }' \
"https://{env}.ap-shanghai.api.tcloudbase.com/v1/databases/-/collections/{collectionName}/delete?mode=JSON"
该请求删除了 a>50
的文档,返回值:
{ "removed": 1 }
removed
指示了匹配并删除的文档数量。
实例:操作 books 集合
下面将演示在一个更接近真实数据的集合 books
上进行增删改查、计数和聚合。首先设定请求的通用参数:
const envId = "{{env}}";
const host = `${envId}.ap-shanghai.api.tcloudbase.com`;
const authorization = "Bearer {{accesstoken}}";
const collectionName = "books";
const method = "POST";
const headers = {
Authorization: authorization,
"X-Host": host,
"Content-Type": "application/json",
};
const baseURL = `https://${host}/v1/databases/-/collections/${collectionName}`;
首先,在这个空集合中添加一些书籍,包含了书名、作者、价格、销量等信息:
async function InsertBooks() {
const books = [
{
id: 1,
name: "The Garden of Forking Paths",
sales: 45,
category: "fiction",
author: {
name: "Jorge Luis Borges",
age: 80,
},
onSale: true,
price: 10.5,
},
{
id: 2,
name: "The Outsider",
sales: 37,
category: "fiction",
author: {
name: "Albert Camus",
age: 46,
},
onSale: false,
price: 29.99,
tags: ["philosophy", "existentialism"],
},
{
id: 3,
name: "Duino Elegies",
sales: 20,
category: "poetry",
author: {
name: "Rainer Maria Rilke",
age: 42,
},
onSale: true,
price: 15.99,
tags: ["poetry", "philosophy"],
},
{
id: 4,
name: "The Red and the Black",
sales: 30,
category: "fiction",
author: {
name: "Stendhal",
age: 35,
},
onSale: true,
price: 15.99,
},
];
const url = `${baseURL}/insert?mode=JSON`;
const resp = await fetch(url, {
method,
headers,
body: JSON.stringify({ docs: books }),
});
const data = await resp.json();
console.log(data);
}
成功插入了 4 条数据:
{
"inserted": 4,
"insertedIds": [
"09a2b1ab638db2700000008354aa6500",
"09a2b1ab638db27000000084374ffb24",
"09a2b1ab638db270000000851cdb3f4e",
"09a2b1ab638db270000000861164410d"
]
}
接着,查询销量大于 30(sales>30
)的书籍,并按降序排列,指定只需要返回书名 name
、销量 sales
和 书籍分类 category
字段:
async function QueryBooks() {
const params = {
query: {
sales: { $gt: 30 },
},
sort: "sales:-1",
projection: "name:1,sales:1,category:1",
};
const url = `${baseURL}/query?mode=JSON`;
const resp = await fetch(url, {
method,
headers,
body: JSON.stringify(params),
});
const data = await resp.json();
console.log(data);
}
调用函数后,可以得到符合条件并按销量降序排列的书籍列表:
{
"offset": 0,
"limit": 0,
"docs": [
{
"_id": "09a2b1ab638db2700000008354aa6500",
"category": "fiction",
"name": "The Garden of Forking Paths",
"sales": 45
},
{
"_id": "09a2b1ab638db27000000084374ffb24",
"category": "fiction",
"name": "The Outsider",
"sales": 37
}
]
}
接下来,对书籍的销量进行更新,将所有销量小于 50(sales<50
)的书籍销量都更新为 50:
async function UpdateBooks() {
const params = {
query: {
sales: { $lt: 50 },
},
update: { $set: { sales: 50 } },
multi: true,
};
const url = `${baseURL}/update?mode=JSON`;
const resp = await fetch(url, {
method,
headers,
body: JSON.stringify(params),
});
const data = await resp.json();
console.log(data);
}
从返回值上,可以看到所有的书籍销量都被更新了:
{ "matched": 4, "modified": 4, "upsertId": "", "newDoc": "" }
为了确认现在书籍的销量都大于 50,使用计数功能进行统计:
async function CountBooks() {
const params = {
query: {
sales: { $gte: 50 },
},
};
const url = `${baseURL}/count?mode=JSON`;
const resp = await fetch(url, {
method,
headers,
body: JSON.stringify(params),
});
const data = await resp.json();
console.log(data);
}
返回值表明前面的操作结果符合预期:
{ "count": 4 }
下面,利用聚合管道统计出价格不高于 20(price<20
)的小说(fiction
),并按降序排列,仅返回指定字段:
async function AggregateBooks() {
const params = {
pipeline: [
{
$project: {
name: "$name",
category: "$category",
canAfford: { $lte: ["$price", 20] },
price: "$price",
},
},
{ $match: { $and: [{ category: "fiction" }, { canAfford: true }] } },
{ $sort: { price: 1 } },
],
};
const url = `${baseURL}/aggregate?mode=JSON`;
const resp = await fetch(url, {
method,
headers,
body: JSON.stringify(params),
});
const data = await resp.json();
console.log(data);
}
在 result
字段中,可以看到聚合结果:
{
"results": [
{
"_id": "09a2b1ab638db2700000008354aa6500",
"canAfford": true,
"category": "fiction",
"name": "The Garden of Forking Paths",
"price": 10.5
},
{
"_id": "09a2b1ab638db270000000861164410d",
"canAfford": true,
"category": "fiction",
"name": "The Red and the Black",
"price": 15.99
}
]
}
最后,删除销量大于等于 50(sales>=50
)的文档,即清空数据:
async function DeleteBooks() {
const params = {
query: {
sales: { $gte: 50 },
},
multi: true,
};
const url = `${baseURL}/delete?mode=JSON`;
const resp = await fetch(url, {
method,
headers,
body: JSON.stringify(params),
});
const data = await resp.json();
console.log(data);
}
返回值:
{ "removed": 4 }
books
集合中所有的数据都被删除了。
云存储
在使用云存储之前,需要先在控制台配置对象存储提供方(当前仅支持腾讯云 COS)。PaaS 云存储 OpenAPI 提供了以下能力:
- 获取对象上传信息
- 获取对象下载信息
- 删除对象
也可以在控制台配置对象存储桶的访问权限或设置缓存。
获取对象上传信息
POST https://{env}.ap-shanghai.api.tcloudbase.com/v1/storages/get-objects-upload-info
请求体是一个 JSON 数组,在请求体的 ObjectId
中写入对象 ID(如:文件名),示例:
curl -X POST \
-H "Authorization: Bearer {{accesstoken}}" \
-H "Content-Type: application/json" \
-d '[{"objectId":"image.png"}]' \
"https://{env}.ap-shanghai.api.tcloudbase.com/v1/storages/get-objects-upload-info"
返回值示例:
[
{
"uploadUrl": "https://cos.ap-shanghai.myqcloud.com/****/image.png", // 上传地址
"downloadUrl": "https://{{env}}-****.tcb.qcloud.la/image.png?sign=04fe912d9f04ed363e641f6590379e94/image.png1670238551\u0026t=1670238551", // 下载地址
"token": "8Blmgy...", // 上传 token,上传到 COS 时携带在 HTTP Header 中
"authorization": "q-sign-algorithm=...", // 上传 authorization,上传到 COS 时携带在 HTTP Header 中
"cloudObjectMeta": "VENCQ2xvdWRPYmplY3RNZXRhLnYxLnRlc3QtMTI1OD...", // 上传元数据信息
"cloudObjectId": "cloud://{{env}}.****/image.png", // 云端对象 ID
"objectId": "image.png" // 传入的对象 ID
}
]
如果获取上传信息出错,将会通过错误码(code
)和错误信息(message
)信息返回,例如:
[
{
"code": "xxx",
"message": "yyy"
}
]
此外,上传时还可以指定 signedHeader
添加额外的签名头部字段,例如添加 MD5:
curl -X POST \
-H "Authorization: Bearer {{accesstoken}}" \
-H "Content-Type: application/json" \
-d '[{"objectId":"image.png","signedHeader":{"content-md5":["{{your-md5}}"]}}]' \
"https://{env}.ap-shanghai.api.tcloudbase.com/v1/storages/get-objects-upload-info"
COS 将会校验 MD5 以保证对象完整性。
MD5 计算方式请查看:COS 相关文档。
获取到文件上传信息后,可通过该信息,将文件上传到 COS
对象存储中。
axios.put(uploadUrl, file, {
headers: {
Authorization: authorization,
"x-cos-meta-fileid": cloudObjectMeta,
"x-cos-security-token": token,
"Content-Type": "image/png",
},
});
注意:浏览器中上传,需在 COS-安全管理-跨域访问 CORS 设置 添加跨域访问规则。
获取对象下载信息
请求方法:POST,请求地址:https://{env}.ap-shanghai.api.tcloudbase.com/v1/storages/get-objects-download-info
请求体是一个 JSON 数组,在请求体的CloudObjectId
中写入云端对象 ID,并可通过maxAge
指定对象有效期。示例:
curl -X POST \
-H "Authorization: Bearer {{accesstoken}}" \
-H "Content-Type: application/json" \
-d '[{"cloudObjectId":"cloud://{{env}}.{{cosInstance}}/image.png","maxAge":120},{"cloudObjectId":"cloud://{{env}}.{{cosInstance}}/404.txt"}]' \
"https://{env}.ap-shanghai.api.tcloudbase.com/v1/storages/get-objects-download-info"
返回值:
[
{
"cloudObjectId": "cloud://{{env}}.{{cosInstance}}/test/404.txt", // 传入的云端对象 ID
"code": "OBJECT_NOT_EXIST", // 错误码
"message": "Storage object not exists" // 错误描述
},
{
"cloudObjectId": "cloud://{{env}}.{{cosInstance}}/video-icon.png",
"downloadUrl": "https://..." // 下载地址
}
]
其中,对于不存在的文件,将返回 OBJECT_NOT_EXIST
的错误码,且 downloadUrl
置空,如文件存在,则通过 downloadUrl
返回下载地址。
删除对象
POST https://{env}.ap-shanghai.api.tcloudbase.com/v1/storages/delete-objects
请求体是一个 JSON 数组,在请求体的 CloudObjectId
中写入云端对象 ID,示例:
curl -X POST \
-H "Authorization: Bearer {{accesstoken}}" \
-H "Content-Type: application/json" \
-d '[{"cloudObjectId":"cloud://{{env}}.{{cosInstance}}/image.png"}]' \
"https://{env}.ap-shanghai.api.tcloudbase.com/v1/storages/delete-objects"
返回值示例:
[
{
"cloudObjectId": "cloud://{{env}}.{{cosInstance}}/image.png" // 传入的 CloudObjectId
}
]
如果文件不存在,将会收到如下的错误码和相应的错误信息:
[
{
"cloudObjectId": "cloud://{{env}}.{{cosInstance}}/not-exist.png",
"code": "OBJECT_NOT_EXIST",
"message": "Storage object not exists"
}
]
实例:上传、下载和删除 COS 中的图片
下面将演示一个更接近实际的例子:在 Node.js 环境中调用云开发 PaaS OpenAPI 进行图片的上传、下载并保存到本地和删除。代码运行环境为 Node.js v16.16.0。
首先,导入使用到的库:
import fetch from "node-fetch";
import fs from "fs";
import path from "path";
import { fileTypeFromBuffer } from "file-type"; // 用于判断文件类型 https://www.npmjs.com/package/file-type
并定义发送请求的通用变量:
const envId = "{{env}}";
const host = `${envId}.ap-shanghai.api.tcloudbase.com`;
const baseURL = `https://${host}/v1/storages`;
const method = "POST";
const headers = {
"X-Host": host,
"Content-Type": "application/json",
Authorization: "Bearer {{accesstoken}}",
};
假设在当前目录下有一张图片 kumanon.jpg
,接下来需要将它上传到 COS,再从 COS 中下载并保存它的副本,最后删除它。第一步,实现用于获取文件上传信息的通用函数:
/**
*
* @param {string} filename 文件名
* @returns 文件上传信息
*/
async function getFileUploadInfo(filename) {
const param = [{ objectId: filename }];
// 获取对象上传信息的请求地址
const url = `${baseURL}/get-objects-upload-info`;
const resp = await fetch(url, {
method,
headers,
body: JSON.stringify(param),
});
const data = await resp.json();
return data;
}
接着,调用它获取上传信息,并完成上传图片到 COS 的操作:
/**
*
* @param {string} filepath 文件路径
*/
async function uploadFileToCOS(filepath) {
// 获取文件上传信息
const filename = path.basename(filepath);
const data = await getFileUploadInfo(filename);
// 从返回值中解构需要用到的变量
const { authorization, cloudObjectMeta, token, uploadUrl } = data[0];
// 读取图片并获取其 mime 类型
const file = fs.readFileSync(filepath);
const { mime } = await fileTypeFromBuffer(file);
// 上传文件到 COS
const resp = await fetch(uploadUrl, {
method: "PUT",
headers: {
"Content-Type": mime,
Authorization: authorization,
"x-cos-meta-fileid": cloudObjectMeta,
"x-cos-security-token": token,
},
body: file,
});
// 打印上传结果
const respCode = resp.status;
if (respCode !== 200) {
const reason = await resp.text();
console.log(reason);
}
console.log(`上传文件 ${filename} ${respCode === 200 ? "成功" : "失败"}`);
}
调用该函数:
uploadFileToCOS("kumanon.jpg");
可以在云开发控制台或者 COS 控制台看到对应图片已被上传:
并可以预览图片:
接下来,实现一个函数用于获取文件下载信息:
/**
*
* @param {string} cloudObjectId 云端文件 ID
* @returns 文件下载信息
*/
async function getFileDownloadInfo(cloudObjectId) {
const param = [{ cloudObjectId, maxAge: 120 }];
// 获取对象下载信息的请求地址
const url = `${baseURL}/get-objects-download-info`;
const resp = await fetch(url, {
method,
headers,
body: JSON.stringify(param),
});
const data = await resp.json();
return data;
}
从云开发控制台复制云端对象 ID(cloudObjectId
),并用它来下载刚刚上传的 kumanon.jpg
并保存到本地:
/**
*
* @param {string} cloudObjectId 云端文件 ID
*/
async function downloadFileFromCOS(cloudObjectId) {
// 获取文件下载地址
const data = await getFileDownloadInfo(cloudObjectId);
const { downloadUrl } = data[0];
const url = encodeURI(downloadUrl);
// 下载文件
const resp = await fetch(url, {
method: "GET",
});
// 获取文件名和文件类型,并将图片保存到本地
const basename = path.basename(url).split("?")[0].split(".")[0];
const timestamp = new Date().getTime();
const file = await resp.arrayBuffer();
const { ext } = await fileTypeFromBuffer(file);
fs.writeFileSync(`${basename}${timestamp}.${ext}`, Buffer.from(file));
}
调用该函数:
downloadFileFromCOS("cloud://{{env}}.{{cosInstance}}/kumanon.jpg");
可以看到图片被下载并以 kumanon${timestamp}.jpg
的名称保存到了当前目录下。
最后,删除这张图片:
/**
*
* @param {string} cloudObjectId 云端文件 ID
*/
async function deleteObject(cloudObjectId) {
const param = [{ cloudObjectId }];
// 删除对象的请求地址
const url = `${baseURL}/delete-objects`;
// 删除对象
const resp = await fetch(url, {
method,
headers,
body: JSON.stringify(param),
});
// 打印删除结果
const data = await resp.json();
if (data[0].code) {
console.log(`删除文件 ${cloudObjectId} 失败`);
console.log("错误信息:", data[0].message);
} else {
console.log(`删除文件 ${cloudObjectId} 成功`);
}
}
调用该函数,将会删除 COS 中的 kumamon.jpg
。