This content originally appeared on DEV Community and was authored by wan x
之前的文章中把云数据库、云存储都讲过了,这一章节要讲解的是云函数。
云函数介绍
云函数其实就是 serverless 技术。可以理解云函数就实现传统后端中的具体业务,而无需关心服务器购买、部署、安全、性能等一系
列相关问题,专注于具体的业务开发。HarmonyOS Next 的云函数采用的是 typescript 的语法,这对熟悉 js 或者熟悉 ArkTs 的同学来说
都很容易上手。
另外云函数具有调用其他云函数、调用第三方接口、调用云存储、调用云数据库的能力。对于段云一体化开发的应用来说,可以根据这样的场景来使用云函数。
- 简单的数据库查询、云端文件的管理可以直接使用客户端操作的方式。
- 繁琐或者涉及安全的操作,可以把业务抽离到云函数端,这样更加容易管理项目。
本章节也会讲解如何云函数的开发、创建、调试、部署,以及在云函数端调用其他云函数、调用第三方接口、调用云存储、调用云
数据库。
创建云函数
可以选择创建云函数或者云对象。这里建议选择云对象更加方便业务逻辑的实现。为什么呢,举个例子。书籍的 crud 刚好放在一个对象中,增、删、改、查都可以做个一个对象的属性存在,更加容易方便管理。比如以下示例。
- 云函数一览
// 云函数
let myHandler = async function (event, context, callback, logger) {
// 这里写不同的业务逻辑,都是都耦合在一个myHandler中
callback();
};
export { myHandler };
- 云对象一览
export class Book {
// 增加
add() {
return {};
}
// 删除
delete() {}
// 修改
update() {}
// 查询
query() {}
}
新建云对象,云对象名称为 book。
得到以下新文件,其中 book.ts
是编写云对象 book 具体业务逻辑的。function-config.json
是关于该云对象的相关配置如是否鉴权等。package.json
是该云对象的描述文件,具体作用类似 oh-package.json
,后续安装第三方依赖也会在这里登记信息。
function-config.json
文件内容如下。
{
"handler": "book.Book",
"functionType": 1,
"triggers": [
{
"type": "http",
"properties": {
"enableUrlDecode": true,
"authFlag": "true",
"authAlgor": "HDA-SYSTEM",
"authType": "apigw-client"
}
}
]
}
相关解析如下
handler 表示云对象的入口
functionType 表示函数类型,“0”表示云函数,“1”表示云对象。“functionType”的值为创建时自动生成,不可手动修改,否则将导致云函数部署失败。
-
triggers 表示触发云对象的函数
- type:触发器类型,配置为“http”。
- properties:触发器属性,属性参数如下表所示。
参数 说明 enableUrlDecode 通过 HTTP 触发器触发函数时,对于 contentType 为“application/x-www-form-urlencoded”的触发请求,是否使用 URLDecoder 对请求 body 进行解码再转发到函数中。true:启用。false:不启用。 authFlag 是否鉴权,默认为 true。 authAlgor 鉴权算法,默认为 HDA-SYSTEM。 authType HTTP 触发器的认证类型。apigw-client:端侧网关认证,适用于来自 APP 客户端侧(即本地应用或者项目)的函数调用。cloudgw-client:云侧网关认证,适用于来自 APP 服务器侧(即云函数)的函数调用。
oh-package.json
文件内容如下。
{
"name": "book",
"version": "1.0.0",
"description": "",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {}
}
相关解释如下。
-
name
:表示项目的名称 -
version
:项目的版本号 -
description
:项目的描述 -
scripts
:一个包含各种脚本命令的对象 -
author
:项目作者信息 -
license
:项目所使用的开源许可证,这里是"ISC"
-
dependencies
:项目的依赖信息
book.ts
book.ts 的文件解析如下。
- methods1表示云对象具体的方法,可以有多个。
- params1、params2是传递给该云对象的参数
- return 的内容是返回给云对象的调用者
调试云函数/对象
在开发云对象时,经常需要编写繁琐的业务逻辑,那么就必不可少对象的调试。DevEco Studio 内置了云对象的调试面板。按照以下步骤操作就可以方便对云对象进行调试了。
- 启动云对象调试,鼠标右键你要调试的云对象、选择 Debug ‘book‘
- 打开云对象调试面板
- 云对象日志面板
当我们在云对象中使用 console.log 调试代码时,日志的输出在这个位置。
需要注意的是当我们修改了云对象的代码时,都需要重新点击 debug book
部署云对象
当云对象开发完毕后,想要客户端调用或者上线生产环境,都需要部署上去。右键你的云对象,选择 Deploy ‘book’ 就可以把你的云对象部署到云端了。你也可以鼠标右键 cloudfouctions 部署或者同步所有的云对象。
如果想要把之前部署到云端的云对象下载下来,选择 Sync book 即可
部署成功,右下角会有相应的提示。
客户端调用云对象
当我们创建好了云对象后,就可以使用客户端直接调用云对象的方法了。
如果是客户端调用云函数,可以参考以下代码。
核心代码如下。
try {
const res = await cloudFunction.call({
// 云对象的名称,这个和你创建的云对象文件名一致
name: "book",
data: {
// book云对象的methods1方法
method: "method1",
// 传递给method1的参数
params: ["a", "b"],
},
});
AlertDialog.show({ message: JSON.stringify(res, null, 2) });
} catch (e) {
console.error(e.message + " " + e.code);
}
这里重点讲解的是客户端调用云对象。
DevEco Studio 提供了方便的方式实现客户端调用云对象的功能。可以让我们想调用普通对象方法一样,直接调用云对象!
具体操作步骤如下。
- 依据云对象 ,在客户端生成云对象的调用模型。 鼠标右键你的云对象 Book。选择 Generate Invoke Interface
- 选择存放该模型文件的路径
- 生成成功后,得到两个关键文件
ImportObject.ts
和Book.ets
ImportObject.ts
文件的主要作用是利用代理 Proxy 的方式,当用户调用Book.method1
方法时,在内部执行了 云函数的调用方法cloudFunction.call
方法。为我们调用云对象提供了便利。代码如下。
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2020-2024. All rights reserved.
* Generated by the Cloud Object compiler. DO NOT EDIT!
*/
import type { BusinessError } from "@kit.BasicServicesKit";
import { cloudFunction } from "@kit.CloudFoundationKit";
export interface CloudObjectLikely {
name: string;
}
function mockMethod<T extends CloudObjectLikely>(
target: T,
version: string,
prop: string | symbol
): (...args: unknown[]) => Promise<unknown> {
return async (...args: unknown[]) =>
new Promise((resolve, reject) => {
cloudFunction
.call({
name: target.name,
version: version,
data: {
method: prop,
params: args,
},
})
.then((value: cloudFunction.FunctionResult) => {
resolve(value.result);
})
.catch((err: BusinessError) => {
reject(err);
});
});
}
export function importObject<T extends CloudObjectLikely>(
tClass: new () => T,
version = "$latest"
): T {
return new Proxy<T>(new tClass(), {
get(target, prop): (...args: unknown[]) => Promise<unknown> {
return mockMethod<T>(target, version, prop);
},
});
}
Book.ets
文件的作用是参考云对象 Book 的模型,生成对应的类,方便我们调用云对象。代码如下。
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2020-2024. All rights reserved.
* Generated by the Cloud Object compiler. DO NOT EDIT!
*/
import type { CloudObjectLikely } from "../ImportObject";
export class Book implements CloudObjectLikely {
public name = "book";
public async method1(
param1: any,
param2: any
): Promise<{
simple: string;
param1: any;
param2: any;
}> {
return Promise.reject(new Error("Method not implemented."));
}
}
- 最后,在客户端中需要导入
Book
和importObject
,再进行调用
// 这里需要对Book进行重命名,因为和之前的数据库类型Book重名了
import { Book as BookCloudObj } from "../cloudobject/book/Book";
import { importObject } from "../cloudobject/ImportObject";
Button("调用云对象14的方法").onClick(this.fn14);
fn14 = async () => {
try {
let bookObj = importObject(BookCloudObj); // 使用importObject实例化BookCloudObj的代理
const res = await bookObj.method1("100", "200");
AlertDialog.show({ message: JSON.stringify(res, null, 2) });
} catch (e) {
console.error(e.message + " " + e.code);
}
};
- 调用结果如图。
云对象调用云对象
在实际开发中,一般情况下,某个具体的业务是存在某个具体的云对象中的,但是必不可少的会出现业务之间的关联。比如查询某一个作者编写过的所有的书籍。作者可以是一个单独的云对象,书籍也是一个单独的云对象,这样就会出现云对象之间调用云对象 需求。我们可以通过 book 云对象调用 auth 云对象来演示。
由于云对象部署到云端后是各自独立的,因此这里不能简单的将多个云对象看成是同一个目录之间的关系,也就是不能 云对象 a 使用相对路径直接导入云对象 b !
新建 auth 云对象 这个看上面的创建 book 云对象步骤即可
调整 auth 云对象的网关设置
function-config.json
中的authType设置为 cloudgw-client
"authType": "cloudgw-client"
- 编写 auth 云对象逻辑代码
export class Auth {
getName(firstName, lastName) {
return { firstName, lastName, fullName: firstName + lastName };
}
}
- book 安装云对象三方库,注意需要在 book 云对象目录下安装
npm install @hw-agconnect/cloud-server
- book 调用 auth 云对象
import { cloud } from "@hw-agconnect/cloud-server";
export class Book {
async method1(param1, param2) {
const res = await cloud.function().call({
// 云对象的名称
name: "auth",
data: {
// 云对象的方法
method: "getName",
// 传递的参数
params: ["万", "大妈"],
},
});
return {
simple: "example",
param1,
param2,
res,
};
}
}
auth 和 book 都部署到云端
客户端测试调用,验证效果
支持,便完成了云对象调用云对象了。
云对象调用云存储
在翻阅了相关文档后,发现云对象对于云存储的支持程度远不够,这里略过。
云对象调用云数据库
云对象中也是需要引入 @hw-agconnect/cloud-server
来操作云数据库的。我们按照以下步骤进行操作。实现查询云对象中查
询数据库的功能。
- 首先在云对象 book 处新建一个文件夹 model,用来存放即将生成的文件
- 在云端生成操作 Book 表格的云对象模块。这里 DevEco Studio 会自动帮我们生成。选择Generate Server Model。
然后选择生成的路径。
- 得到文件
model/book.ts
,这里为了和之前的book.ts
区分,我们把它名称修改成model/bookModel.ts
。文件中的类名也修改成BookModel
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2020-2023. All rights reserved.
* Generated by the CloudDB ObjectType compiler. DO NOT EDIT!
*/
class BookModel {
id: number;
name: string;
price: number;
publish: Date;
hot: boolean;
cover: string;
constructor() {}
getFieldTypeMap(): Map<string, string> {
let fieldTypeMap = new Map<string, string>();
fieldTypeMap.set("id", "Integer");
fieldTypeMap.set("name", "String");
fieldTypeMap.set("price", "Double");
fieldTypeMap.set("publish", "Date");
fieldTypeMap.set("hot", "Boolean");
fieldTypeMap.set("cover", "String");
return fieldTypeMap;
}
getClassName(): string {
return "Book";
}
getPrimaryKeyList(): string[] {
let primaryKeyList: string[] = [];
primaryKeyList.push("id");
return primaryKeyList;
}
getIndexList(): string[] {
let indexList: string[] = [];
indexList.push("id");
indexList.push("price");
return indexList;
}
getEncryptedFieldList(): string[] {
let encryptedFieldList: string[] = [];
return encryptedFieldList;
}
setId(id: number): void {
this.id = id;
}
getId(): number {
return this.id;
}
setName(name: string): void {
this.name = name;
}
getName(): string {
return this.name;
}
setPrice(price: number): void {
this.price = price;
}
getPrice(): number {
return this.price;
}
setPublish(publish: Date): void {
this.publish = publish;
}
getPublish(): Date {
return this.publish;
}
setHot(hot: boolean): void {
this.hot = hot;
}
getHot(): boolean {
return this.hot;
}
setCover(cover: string): void {
this.cover = cover;
}
getCover(): string {
return this.cover;
}
static parseFrom(inputObject: any): BookModel {
let result = new BookModel();
if (!inputObject) {
return result;
}
if (inputObject.id) {
result.id = inputObject.id;
}
if (inputObject.name) {
result.name = inputObject.name;
}
if (inputObject.price) {
result.price = inputObject.price;
}
if (inputObject.publish) {
result.publish = new Date(inputObject.publish);
}
if (inputObject.hot) {
result.hot = inputObject.hot;
}
if (inputObject.cover) {
result.cover = inputObject.cover;
}
return result;
}
}
export { BookModel };
- 新建文件
bookController.ts
,负责组合 对 book 实例的 CURD 操作。
import { cloud, CloudDBCollection } from "@hw-agconnect/cloud-server"; //引入Server SDK依赖
import { BookModel } from "./model/BookModel"; //BookModel为对象类型名
// ZONE_NAME为存储区名称
const ZONE_NAME = "Study";
export class BookCtroller {
collection: CloudDBCollection<BookModel>;
constructor() {
this.collection = cloud
.database({ zoneName: ZONE_NAME })
.collection(BookModel);
}
//查询数据
async queryBooks() {
let query = this.collection.query();
return await query.get();
}
//更新数据
async upsertBooks(records: BookModel[]) {
return await this.collection.upsert(records);
}
//删除数据
async deleteBooks(records: BookModel[]) {
return await this.collection.delete(records);
}
}
- 最后在云对象 book 中添加一个查询方法 query。
// 查询数据库
async query() {
let bookCtroller = new BookCtroller();
const result = await bookCtroller.queryBooks()
return {
result
}
}
- 测试调用
其他的数据库操作可以基于该模式进行拓展。
云对象调用第三方 api
如想要调用其他的 api,比较简单的方式可以直接安装 axios,然后像调用接口一样使用 axios 即可。
总结
- 云函数介绍:云函数即 serverless 技术,采用 TypeScript 语法,开发者无需关注服务器相关问题,专注业务开发。它具备调用其他云函数、第三方接口、云存储及云数据库的能力。简单数据库查询等操作可在客户端进行,繁琐或涉及安全的操作适合放在云函数端。
-
创建云函数:建议选择创建云对象,以书籍的 CRUD 为例,将其放在一个对象中更便于管理业务逻辑。创建云对象后会生成
book.ts
(编写业务逻辑)、function - config.json
(云对象配置,如入口、函数类型、触发器等)、package.json
(类似oh - package.json
,记录项目信息及依赖)。 - 调试云函数 / 对象:在 DevEco Studio 中,右键要调试的云对象选择 “Debug ‘book’” 启动调试,可在云对象调试面板和日志面板查看相关信息。修改代码后需重新点击 “debug book”。
- 部署云对象:开发完成后,右键云对象选择 “Deploy ‘book’” 可部署到云端,也可右键 “cloudfouctions” 部署或同步所有云对象。若要下载已部署的云对象,选择 “Sync book”。
-
客户端调用云对象:DevEco Studio 提供便捷方式,通过右键云对象选择 “Generate Invoke Interface” 生成调用模型,选择存放路径后得到
ImportObject.ts
(利用代理执行云函数调用方法)和Book.ets
(参考云对象模型生成的类)。在客户端导入相关文件后即可调用云对象方法。 -
云对象调用云对象:以 book 云对象调用 auth 云对象为例,需新建 auth 云对象并调整网关设置(
function - config.json
中authType设为cloudgw - client
),编写 auth 云对象逻辑代码,在 book 云对象目录下安装云对象三方库@hw - agconnect/cloud - server
,然后在 book 云对象中调用 auth 云对象,最后将两个云对象部署到云端并在客户端测试调用。 - 云对象调用云存储:文档显示云对象对云存储支持不足,故略过。
-
云对象调用云数据库:在云对象 book 处新建文件夹 model,通过 DevEco Studio 生成操作 Book 表格的云对象模块,得到
bookModel.ts
文件并修改相关内容。新建bookController.ts
文件负责组合对 book 实例的 CURD 操作,最后在云对象 book 中添加查询方法并进行测试调用。 - 云对象调用第三方 api:调用其他 api 较简单的方式是安装 axios,然后像调用接口一样使用。
参考文档
如果你兴趣想要了解更多的鸿蒙应用开发细节和最新资讯,欢迎在评论区留言或者私信或者看我个人信息,可以加入技术交流群。
This content originally appeared on DEV Community and was authored by wan x