Skip to content

云函数入门

云函数是运行在云端的 JavaScript 代码。

云函数可使用 Typescript 编写,无需管理服务器,在开发控制台在线编写、在线调试、一键保存即可运行后端代码。

在你的应用中,大多数数据的获取都可在客户端直接操作数据库,但是通常业务中会使用到「非数据库操作」,如注册、登录、文件操作、事务、第三方接口等,可直接使用云函数实现。

第一个云函数

一个最简单的云函数只需要在模块中导出一个名为 main 的函数,如下面代码所示:

exports.main = function () {
  return "hello world!";
};
1
2
3

当然,使用 ESModule 的语法也是可以的:

export function main() {
  return "hello world!";
}
1
2
3

访问云函数

通过 URL 访问云函数

发布云函数后,可以在云函数列表中的"调用地址"获得云函数的访问地址。

使用浏览器或者 PostMan 等工具访问该地址,即可得到 hello world!字符串。

通过 SDK 访问云函数

除了通过 HTTP 请求来访问,还可以使用 laf-client-sdk 来访问云函数。

INFO

目前 SDK 暂时只支持发送 POST 请求

首先,安装 SDK:

npm i laf-client-sdk
1

接下来,需要创建一个cloud 对象:

import { Cloud } from "laf-client-sdk";

const cloud = new Cloud({
  baseUrl: "xxx", // 这个地址可以在欢迎页面中的“服务地址”中找到
  getAccessToken: () => "", // 这里不需要授权,先填空
});
1
2
3
4
5
6

然后,就可以调用云函数了:

const ret = await cloud.invokeFunction("helloworld");

console.log(ret); // hello world!
1
2
3

获取用户传递的参数

刚刚介绍的云函数只能静态地返回一些内容,但在实际场景下,我们需要让云函数能够和用户交互。

main 函数中,可以通过第一个参数 ctx 来获取用户传递的请求信息。

ctx 具有下面的一些内容:

属性介绍
ctx.requestId当前请求的唯一 ID
ctx.method当前请求的方法,如GETPOST
ctx.headers所有请求的 headers
ctx.auth使用 Http Bearer Token 认证时,解析出的 token 值
ctx.query当前请求的 query 参数
ctx.body当前请求的 body 参数
ctx.responseHTTP 响应,和expressResponse实例保持一致
ctx.socketWebSocket 实例
ctx.files上传的文件 (File 对象数组)

下面的例子可以读取用户传递的 Query 参数username

exports.main = function (ctx) {
  return `hello, ${ctx.query.username}`;
};
1
2
3

访问 调用地址?username=test,你将得到:

hello, test;
1

在客户端 SDK 调用带参数的云函数

invokeFunction 函数的第二个参数指明了用于发送的数据,这个数据会以 Body 的形式发送:

const ret = await cloud.invokeFunction("函数名", { name: "test" });
1

异步的云函数

刚刚我们提到的云函数都是同步函数。但是,在实际应用中,云函数需要执行的异步操作(如网络请求)。

幸运的是,云函数本身是支持异步调用的,你只需要在函数的前面加上 async ,就能轻松的让函数支持异步操作:

exports.main = async function (ctx) {
  await someAsyncAction;
  return `hello, ${ctx.query.username}`;
};
1
2
3
4

云函数的返回值

云函数的返回值支持多种类型:

Buffer.from("whoop"); // Buffer
{
  some: "json";
} // 对象,会被处理成JSON
("<p>some html</p>"); // HTML
("Sorry, we cannot find that!"); // 字符串
1
2
3
4
5
6

如果需要发送状态码,则需要使用 ctx 对象上的 response 属性:

ctx.response.status(403); // 发送403状态码
1

导入模块

我们可以很轻松地借助 ESModule 的 import 语法或 CommonJS 的 require 语法来导入模块。

WARNING

不建议使用 require 引入包,虽然也能运行,但在线 IDE 无法给出智能提示

导入 Node.js 内置包

下面的例子使用了 Node.js 内置的包 crypto,来对密码进行哈希:

import cloud from "@/cloud-sdk";
import * as crypto from "crypto";

exports.main = async function (ctx) {
  const { password } = await ctx.body;

  const password_hash = crypto
    .createHash("sha256")
    .update(content)
    .digest("hex");

  return password_hash;
};
1
2
3
4
5
6
7
8
9
10
11
12
13

导入 NPM 包

在使用 npm 包之前,需要在 依赖管理 处安装对应的包。

import cloud from "@/cloud-sdk";
import * as dayjs from "dayjs";

exports.main = function () {
  return dayjs().format();
};
1
2
3
4
5
6

导入云函数

目前 Laf 暂不支持导入其他的云函数,敬请期待。

INFO

虽然不支持导入,但支持执行其他的云函数。

Cloud SDK

刚刚编写的一些云函数都是比较基础的一些功能,但并没有和 Laf 的其他功能连接起来。

在云函数上,Laf 提供了云 SDK @/cloud-sdk 让云函数支持访问网络、数据库、对象存储等。

WARNING

@/cloud-sdk 是一个专有的模块,只能在云函数上使用,不支持通过 npm 安装到其他位置。

导入 SDK

SDK 的所有内容通过它的默认导出来访问。

import cloud from "@/cloud-sdk";
1

发送网络请求

使用 cloud.fetch() 可发起 HTTP 请求,调用三方接口,可完成如支付接口、短信验证码等等三方接口操作。

该接口是对 axios 请求库的封装,其调用方法与 axios 完全一致。

import cloud from "@/cloud-sdk";

exports.main = async function (ctx) {
  const ret = await cloud.fetch({
    url: "http://api.github.com/",
    method: "post",
  });

  console.log(ret.data);
  return ret.data;
};
1
2
3
4
5
6
7
8
9
10
11

操作数据库

通过cloud.database() 可以获取数据库对象,进而对数据库进行操作。

INFO

数据库 API 的详细操作方法可以参考 云数据库 章节

下面的例子可以获取数据库中的用户信息:

import cloud from "@/cloud-sdk";

exports.main = async function (ctx) {
  const { username } = ctx.body;
  // 数据库操作
  const db = cloud.database();
  const ret = await db.collection("users").where({ username }).get();

  console.log(ret);
  return ret.data;
};
1
2
3
4
5
6
7
8
9
10
11

生成 JWT token

以下实现简单登录函数,以演示 标准 JWT token 的生成,预期开发者已熟悉 JWT 相关知识。

可查看JSON Web Token 入门教程

注意:出于演示目的,对 password 以明文方式查询,并未做 hash 处理考虑,不建议实际开发过程中如此使用。

import cloud from "@/cloud-sdk";

exports.main = async function (ctx) {
  const { username, password } = ctx.body;

  const db = cloud.database();
  const { data: user } = await db
    .collection("users")
    .where({ username, password })
    .getOne();

  if (!user) {
    return "invalid username or password";
  }

  // payload of token
  const payload = {
    uid: user._id,
    // 默认 token 有效期为 7 天,请务必提供此 `exp` 字段,详见 JWT 文档。
    exp: Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 7,
  };
  const access_token = cloud.getToken(payload);

  return {
    access_token,
    uid: user._id,
    username: user.username,
    expired_at: payload.exp,
  };
};
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

Apache License V2.0