云函数开发指南
收藏
我的收藏

介绍​

开发者可在服务列表界面创建函数服务,在web界面内使用Node js 14语言开发相关接口功能后,供前端相关应用(小程序,小游戏,小玩法,网页应用等)侧使用。​

操作指引​

使用限制​

当前云函数功能采用定向邀测政策,需填写工单,申请通过后才可使用。​

创建服务​

在dev环境,服务列表界面选择新建服务,填入服务名称和服务简介,选择服务类型为云函数。​
填写完成后需等待服务创建,此时服务会使用模板代码默认在dev环境发布一次。
初始化完成后在prod环境会创建同名服务,注意在 prod环境的云函数服务不支持代码编辑,建议在dev环境通过充分调试和发布自测后,再将prod环境对应的服务按灰度发布。

云函数开发​

如上图,左侧为对应文件夹,云函数文件和 package.json文件,中间为函数开发界面,右侧为云函数调试界面。​

云函数文件&文件夹创建​

在左侧选择对应icon可选择创建文件夹和js文件,目前支持最多创建10个文件夹和50个js文件。​
选中对应文件夹后,选择新建文件,填入js文件名称和函数描述后,可在对应文件夹下新建js文件。​
注意:相同目录下不支持js文件和文件夹重名。文件夹或者文件删除后,也不支持再次创建同名文件或者文件夹。​

云函数开发与调试​

在文本编辑器界面采用Node js 14语法开发云函数业务逻辑功能,目前支持 CommonJS 规范。右侧可对当前云函数进行调试,如下图。​
调试具体功能可见:云函数如何调试
params和context 功能具体可见:云函数API
npm包如何使用:可见”开发指南“中的”如何使用npm包“模块。​

dev环境云函数服务发布​

在对云函数代码进行充分调试后,可选择发布代码,如下图,点击发布后会跳转至发布页面,展示当前云函数有哪些文件及代码修改,选择发布哪些修改的文件,填入相关发布备注和发布设置,进行发布。​
发布部署界面:​

dev环境云函数服务调用​

在部署完成后可选择域名或者callContainer方式调用:具体可见“开发指南”,“云函数调用方式”中的“线上调用”模块。​

prod环境云函数发布​

进入服务对应的prod环境界面,选择发布后,填入发布信息,可进行prod环境服务的发布。​
prod 环境的云函数服务发布后,也可采用callContainer 和域名 2种方式调用,具体可见“开发指南”,“云函数调用方式”中的“线上调用”模块,注意环境ID需改成prod环境。​

开发指南​

如何使用npm 包​

在package.json 中默认安装5个npm包,分别为​
    1.抖音云云数据库npm包,使用文档:云数据库服务端使用
    2.tos 文件存储 npm 包。使用文档:https://www.volcengine.com/docs/6349/113480
    3.axios 为前端通用网络请求库,dayjs 为日期库,lodash 为相关工具库。​
如何添加或者删除npm包。​
在package.json的dependencies字段中添加对应npm包名和版本,npm包版本解释如下:https://zhuanlan.zhihu.com/p/616051512?utm_id=0
若想删除npm包,则在dependencies 中删除对应npm包。​
在编辑完package.json后,需选择对应package.json文件进行一次发布,才能在调试环节使用对应的npm包。
在云函数内通过require方式引入对应npm包后使用相关npm api开发。​

如何开发 TS ​

新创建一个 ts 函数服务​

在函数服务创建时可勾选"typescript",表明是否创建 ts 函数服务模版。​
创建的云函数服务里会有对应的 ts 语法配置文件 tsconfig.json,和在 package.json 中增加 ts 相关包。​
ts 云函数服务模版代码如下所示,可调用 node-server-sdk 中的能力,获取 openId 等相关上下文信息,和进行服务间调用以及 openAPI 方法调用,也可删除相关模版代码,开发业务相关 ts 函数逻辑。开发完成后需导出一个默认函数,其中 params 和 context 功能与 js 模版中相同。​
TypeScript
复制
/**
* @param params 调用参数,HTTP 请求下为请求体
* @param context 调用上下文
*
* @return 函数的返回数据,HTTP 场景下会作为 Response Body
*
*/
import { dySDK } from '@open-dy/node-server-sdk';
export default async function (params: any, context: any) {
return {
message: 'hello',
};
};
// 传入默认的 context 参数, 获取 openId 等信息,样例函数不使用可删除
function getContext(context: any) {
const serviceContext = dySDK.context(context);
return serviceContext.getContext();
}
// 传入默认的 context 参数, 及需要调用的服务id, path, 请求方法和内容等,进行服务间调用,样例函数不使用可删除
async function callContainer(context: any, serviceId: string,
path: string,
method: string,
querys?: Record<string, any>,
data?: any,
headers?: Record<string, any>) {
const serviceContext = dySDK.context(context);
return serviceContext.callContainer({
serviceId,
path,
method,
querys,
data,
headers,
});
}
// 传入默认的 context 参数, 及openApi 对应的 url, method 等参数,进行 openApi 调用,样例函数不使用可删除
async function openApiInvoke(context: any, url: string,
method: string,
querys?: Record<string, any>,
data?: any,
headers?: Record<string, any>) {
const serviceContext = dySDK.context(context);
return serviceContext.openApiInvoke({
url,
method,
querys,
data,
headers
})
}
也可将 ts 文件修改为 js 文件。但需将文件内容修改为 js 语法。否则会编译报错。​
在新建函数时默认开启 TypeScript 选项,表示创建 ts 函数文件。​

存量 js 函数服务升级为 ts 函数服务​

在项目里选择启用 TypeScript后,会默认创建 tsconfig.json 文件和在 package.json 中增加 ts 相关包。​
可将对应 js 文件修改为 ts 后缀文件,文件内容保持不变。​

package.json 更新​

开通新服务后,在修改 package.json 时,无需发布服务,即可在调试时使用最新 npm 包。​

@open-dy/node-server-sdk 中相关方法说明​

获取用户信息​

获取 openId 等用户信息。在 dySDK.context 中传入云函数上下文参数(context)。获取 serviceContext 实例,调用 getContext 返回 openId 等信息。​
TypeScript
复制
import { dySDK } from '@open-dy/node-server-sdk';
export default async function (params: any, context: any) {
const serviceContext = dySDK.context(context);
return serviceContext.getContext();
};
目前返回的信息如下所示:​
TypeScript
复制
source: 调用来源,
ip: 调用IP地址,
appId: 调用appId,
envId: 调用环境Id,
openId: 用户的openId,在调试环境下为空,
unionId: 用户的unionId,在调试环境下为空,
anonymousOpenid: 用户的匿名openId,在调试环境下为空。

服务间调用​

调用同个环境下其余已发布服务的接口path。调用方式和传参如下所示:​
TypeScript
复制
import { dySDK } from '@open-dy/node-server-sdk';
export default async function (params: any, context: any) {
const serviceContext = dySDK.context(context);
try {
const res = await serviceContext.callContainer({
serviceId: "123445", // 服务id
path: "/example", // 调用路径
method: "GET", // 调用方法
querys: { "name": 1 }, // GET 时的请求参数
data: { "data": 1 }, // POST 时的请求参数
headers: { "header": 1 }, // 请求头
});
console.log("res", res);
} catch (err) {
console.log(err);
}
};

openAPI 调用

调用支持抖音云免鉴权的 openAPI。相关参数内容可在开放平台相关服务端 openAPI 文档中查看。​
TypeScript
复制
import { dySDK } from '@open-dy/node-server-sdk';
export default async function (params: any, context: any) {
const serviceContext = dySDK.context(context);
try {
const res = await serviceContext.openApiInvoke({
url: "https://minigame.zijieapi.com/mgplatform/api/apps/qrcode", // openAPI对应的 url。
method: "POST", // openAPI 调用方式,
headers: {"Content-Type":"application/json"}, // openAPI 请求头
querys: {"name": "ckq"}, // openAPI GET 调用时对应的请求参数
data: { "appname": "douyin", "path": "/", "width": 0, "line_color": { "r": 0, "g": 0, "b": 0 }, "background": { "r": 255, "g": 255, "b": 255 }, "set_icon": false } // openAPI POST 时对应的请求参数
});
console.log("res", res);
} catch (err) {
console.log(err);
}
};

云函数调用方式&功能函数调用方式​

线上调用​

目前云函数服务线上支持2种调用方式,分别为域名调用和callContainer 调用,具体调用方式如下:​

域名调用​

在访问控制页面,打开域名访问,配置访问路径及路径名。访问路径具体配置可参考 访问路径配置,​
一般配置路径名为/,访问路径为/*。​
可修改对应域名为自定义域名,具体自定义域名配置参考 自定义域名配置。​
配置完成后,在浏览器中输入对应域名+云函数路径(云函数在文件夹内需加上对应文件夹路径)。进行访问,如下:​

小程序,小游戏,小玩法callContainer侧使用​

在小程序开发者工具内采用callContainer调用,注意路径为云函数文件路径,代码如下:​
JavaScript
复制
const cloud=tt.createCloud({
envID:'env-xxxxxxxNP',
serviceID:'1xxxxxxxxk'
});
cloud.callContainer({
path:'/index',
init:{
method:'POST',
header:{
'content-type': 'application/json',
},
body:{
example:'example',
},
timeout: 60000,//ms
},
success:({statusCode, header, data})=>{
JSON.parse(data)
},
fail: console.warn,
complete: console.warn,
})
完成后选择真机调试。可在真机console tab页面看到对应信息。如下:​

调用路径​

域名或者callContainer调用时需路径为云函数文件所在路径,如有以下文件目录:​
则调用根目录下的index 函数对应path 为 /index 或者/ 。​
调用根目录下的add 函数对应path 为 /add。​
调用sub 目录下的index 函数对应path 为 /sub/index 或者 /sub/。 若访问文件夹且不增加具体云函数名称则系统默认去调用目录下的index云函数。​
调用sub 目录下的sub函数对应path 为 /sub/sub。​
在云函数内需要有默认异步 exports 函数导出,才能被正确调用,如下,否则在调用时会报会报导出的内容不是一个函数:​
JavaScript
复制
module.exports = async function (params, context) {
return {
message: dayjs(),
};
};

功能函数调用​

按照 CommonJS 语法可在add文件中导出对应功能函数如下:​
在index文件中通过require方式导入并且使用,如下:​
此时add 函数仅作为功能函数,被其余云函数间接调用使用,而不能在线上直接调用。

云函数间调用​

在add 函数中添加如下默认导出代码:​
此时可在index 函数中通过require方式导入add中的默认导出函数并且传入params 和context。​
此时在调用index 函数时在 add 函数内可获得index 函数的params和context,同时add函数也支持线上调用。​

发布方式​

在dev环境开发完云函数功能后,点击发布,进入云函数发布页面。​
选择对应文件和填入发布备注,进行dev环境发布。​
在prod 环境选择对应服务,若未发布过,则可进行一次灰度发布。​
prod环境对应云函数服务不支持代码编辑,调式时的调用结果与线上调用保持一致。​

代码回滚​

在右侧发布记录里选择回滚后,进入回滚界面,选择对应版本进行回滚。此时系统会使用对应回滚版本的代码发布一次。​

注意事项​

避免使用全局变量​

抖音云云函数底层运行时多实例的,且会根据请求量实时动态扩缩容,无法保证每一次请求都访问到同一个实例中。因此,应该尽量避免使用全局变量来保存值,因为这将导致不符合预期的结果。​
例如:​
JavaScript
复制
// Using global variables can lead to unexpected results
let someGlobalVar = 0;
module.exports = async function(params, context) {
// The original value of `someGlabalVar` is unpredictable
someGlobarVar += 1;
// An unexpected return value
return {
someGlobarVar,
};
}
若对于函数中有全局变量存储需求,建议使用云数据库,参见:服务端云数据库使用。​

避免写死循环代码​

切记不要写死循环等高危代码,可能会导致后续调试功能不可用。​

超时时间​

目前线上调用的默认超时时间为60s, 调试时默认超时时间是10s,因此建议不要写执行时间超过10s的异步代码,如下:​

错误处理​

针对开发者代码执行出错,系统会默认返回code 为-1 及对应错误信息,对应http 状态码为500,http状态码不可修改。​
对应错误也会在日志平台打印。​
对于系统错误,例如针对开发者输入的path 找不到对应执行的云函数,也会抛出对应错误code和错误内容,如下:​

返回内容​

若返回为一个Buffer 二进制数据,在调试时会将其转换成base64字符串,线上返回对应二进制数据。​
若返回为一个非法对象,则系统会默认抛出相关错误,如下:​

跨域​

目前在云函数响应头里系统默认加上了Access-Control-Allow-Origin,等跨域响应头,开发者可根据需要通过context.set方式自行修改,建议无需修改Access-Control-Allow-Headers,保持 * 即可。如下:​

调用路径​

线上调用路径是与文件夹名称及文件名称强绑定的,因此在修改文件夹名称或者文件名称时需注意对线上相关调用路径进行修改。​