基于函数创建插件
在AgentArts智能体开发平台中,当官方插件市场无法满足特定业务需求时,开发者需要自主创建插件。根据实现机制与运行形态的不同,自定义插件主要分为“API类型插件”和“函数类型插件”两种形态。API型插件介绍及创建请参考基于API创建插件。
前提条件
- 已开通AgentArts服务。
- 登录用户为空间所有者、空间管理员、开发工程师,详细信息请参考管理团队空间成员。
函数形式插件
函数类型插件是指直接在AgentArts智能体开发平台中编写并运行的一段代码脚本(Python3.9或Node.js14.18脚本),它不依赖外部服务器,而是利用平台提供的算力即时执行。
典型适用场景:
- 精确计算:利息计算、日期推算(下周三是几号)、单位换算。
- 逻辑校验:身份证/手机号正则校验、JSON格式修复。
- 数据清洗:数据进行去重、排序、过滤。
不适用场景:大规模数据存储、重型计算(如视频渲染)、复杂的持久化状态管理。
插件调用链路:
- 用户输入:修复这段JSON:{'name': '张三', age: 25,}。
- Agent分析:Agent识别用户意图为“JSON修复”,命中代码插件fix_json_format。
- 参数生成:模型提取用户提供的原始文本,生成入参:{ "raw_text": "{'name': '张三', age: 25,}" }。
- 沙箱启动:Agent启动一个隔离的Python运行环境(Sandbox)。
- 代码执行:加载用户编写的修复逻辑,代码尝试解析并重新序列化数据,确保输出符合标准JSON规范。
- 返回结果:代码运行结束,返回结构化结果:{ "is_valid": true, "formatted_json": "{\"name\": \"张三\", \"age\": 25}" }。
- 最终回复:模型根据代码返回的结果,向用户输出:“已为您修复JSON格式,修复后的内容如下...”。
创建插件的流程
函数型插件是直接在平台提供的沙箱环境中的一段脚本代码,本文将直接通过具体示例进行演示,助您快速上手。
|
序号 |
流程环节 |
说明 |
|
|---|---|---|---|
|
1 |
创建插件 |
在函数插件中,“插件”仅作为管理和分类的容器,实现对同类工具的管理。 |
|
|
2 |
创建工具 |
创建工具 |
工具真正干活的实体。每一个工具都对应一个独立的函数实例。代码逻辑、依赖包、入参出参定义全部都在这里配置。 |
|
创建自定义依赖包(可选) |
支持使用Python3.9或Node.js14.18创建工具代码。为了保持轻量和安全,平台只提供最基础的语言环境,即除了Python3.9、Node.js14.18本身自带的标准库外,其余依赖包均需要手动上传。 |
||
|
示例1 |
文本相似度计算插件,基于Python,不需上传依赖包。 |
||
|
示例2 |
网页HTML内容清洗插件(需上传依赖包),基于Python,需上传依赖包。 |
||
|
示例3 |
|||
|
附录1 |
|||
|
附录2 |
|||
示例1:文本相似度计算插件
该插件的主要作用是接收两个文本输入(text1和text2),并通过以下三种算法之一计算它们的相似程度(0.0到1.0之间):
- Cosine(余弦相似度):默认算法。通过词频向量计算文本在语义/内容上的重合度。
- Jaccard(杰卡德相似系数):计算两个文本中相同字符(token)在总字符中的占比,适合集合重合度计算。
- Edit Distance(编辑距离):计算将一个文本变成另一个文本需要变动多少字符,适合检测拼写错误或短文本的字面差异。
同时配置了停用词表(DEFAULT_STOPWORDS)、预处理配置(PREPROCESS_CONFIG)、文本预处理(preprocess_text)单元。
- 停用词表:定义了一组常见的无实际意义的词(如“的”、“了”、“是”等),用于过滤。
- 预处理配置:转小写;去除标点符号(只保留汉字、字母、数字);去除停用词;切分粒度。
- 文本预处理:清洗:将文本转为小写,并使用正则表达式;分词:将文本打散成字符列表;过滤:移除在停用词表中的字符。
文本相似度计算插件创建步骤如下:
- 登录AgentArts智能体开发平台,在左侧导航栏“个人空间”区域,选择目标空间。
- 在左侧导航栏中选择“开发中心 > 组件库”,在“插件”页签,单击页面右上角“创建插件”。
- 选择“函数类型”类型的插件,然后根据以下步骤配置插件信息。
表1 基本信息 参数
说明
示例
插件类型
根据实现机制与运行形态的不同,插件分为“API类型”和“函数类型”两种形态。
函数类型
插件图标
单击默认图标按钮,可上传本地图片作为插件的自定义图标。
支持jpg、jpeg、png格式,不超过200KB。
系统默认图标
名称
用于标识当前插件,在“组件库 > 插件”页面会展示该名称。
命名规则:按照插件的实际功能命名,有助于Agent进行插件的精准识别和调度。
命名要求:可以包含中文、英文、数字、下划线;
长度限制:2~64个字符。
文本相似度计算
描述
描述当前插件的类型、功能和适用场景。
需要按照插件的实际功能填写描述,有助于Agent进行插件的精准识别和调度。
使用Python内置库(re/math/difflib)计算两段文本的相似度(适配Agent意图匹配、问答匹配、文本查重等场景)。
- 配置完单击“确定”。
平台会自动跳转至工具信息页面,请参考后续步骤创建工具,在创建工具阶段会配置代码脚本、输入、输出参数等信息。
- 在“工具信息”页面,单击“创建工具”,在“添加工具”弹窗单击“新建函数”。
图1 添加函数
- 填写函数名称与描述,执行语言选择“Python3.9”。
表2 函数基本信息 参数
填写示例
名称
Text_similarity_calculation
描述
使用Python内置库(re/math/difflib)计算两段文本的相似度(适配Agent意图匹配、问答匹配、文本查重等场景)。
执行语言
Python3.9
- 单击“编辑源码”,复制如下代码脚本。
图2 编辑源码
# -*- coding:utf-8 -*- import re import math import difflib # ===================== 全局配置 ===================== DEFAULT_STOPWORDS = { "的", "了", "是", "我", "你", "他", "她", "它", "们", "在", "有", "就", "不", "和", "也", "都", "这", "那", "此", "彼", "之", "于", "及", "与", "哦", "啊", "呢", "吧", "吗", "哈", "哎", "哼", "嗨", "喂", "嗯", "一个", "一些", "一点", "一般", "一样", "怎么", "怎么样", "哪里", "什么", "多少" } DEFAULT_ALGORITHM = "cosine" PREPROCESS_CONFIG = { "lowercase": True, "remove_punctuation": True, "remove_stopwords": True, "split_granularity": "char" } # ===================== 文本处理工具函数 ===================== def preprocess_text(text: str, config: dict = None) -> list: if text is None: text = "" config = config or PREPROCESS_CONFIG text = str(text).strip() if config.get("lowercase", True): text = text.lower() if config.get("remove_punctuation", True): text = re.sub(r"[^\u4e00-\u9fa5a-zA-Z0-9\s]", "", text) if config.get("split_granularity", "char") == "char": tokens = list(text) else: tokens = text.split() if config.get("remove_stopwords", True): tokens = [t for t in tokens if t and t not in DEFAULT_STOPWORDS] return tokens def cosine_similarity(vec1: list, vec2: list) -> float: if not vec1 or not vec2: return 0.0 dot_product = sum(v1 * v2 for v1, v2 in zip(vec1, vec2)) norm1 = math.sqrt(sum(v * v for v in vec1)) norm2 = math.sqrt(sum(v * v for v in vec2)) if norm1 == 0 or norm2 == 0: return 0.0 return round(dot_product / (norm1 * norm2), 4) def jaccard_similarity(tokens1: list, tokens2: list) -> float: set1 = set(tokens1) set2 = set(tokens2) intersection = len(set1 & set2) union = len(set1 | set2) return round(intersection / union, 4) if union != 0 else 0.0 def edit_distance_similarity(text1: str, text2: str) -> float: text1 = str(text1).strip() if text1 is not None else "" text2 = str(text2).strip() if text2 is not None else "" return round(difflib.SequenceMatcher(None, text1, text2).ratio(), 4) # ===================== 平台入口函数 ===================== def main(args: dict) -> dict: """ 平台标准入口函数,函数名不可修改 :param args: 输入参数字典,包含 text1、text2、algorithm :return: 输出参数字典,包含相似度计算结果 """ try: # 1. 获取输入参数 text1 = str(args.get('text1', '')).strip() text2 = str(args.get('text2', '')).strip() algorithm = str(args.get('algorithm', DEFAULT_ALGORITHM)).strip().lower() # 2. 非空校验 if not text1 or not text2: return { "similarity": "0.0", "status": "failed", "used_algorithm": "", "confidence": "0.0", "error_msg": "text1 和 text2 不能为空,请检查输入参数" } # 3. 计算相似度 if algorithm == "jaccard": tokens1 = preprocess_text(text1) tokens2 = preprocess_text(text2) similarity = jaccard_similarity(tokens1, tokens2) used_algorithm = "jaccard" elif algorithm == "edit_distance": similarity = edit_distance_similarity(text1, text2) used_algorithm = "edit_distance" else: tokens1 = preprocess_text(text1) tokens2 = preprocess_text(text2) vocab = {token: idx for idx, token in enumerate(set(tokens1 + tokens2))} vec1 = [tokens1.count(token) for token in vocab] vec2 = [tokens2.count(token) for token in vocab] similarity = cosine_similarity(vec1, vec2) used_algorithm = "cosine" # 4. 返回成功结果 return { "similarity": str(similarity), "status": "success", "used_algorithm": used_algorithm, "confidence": str(similarity), "error_msg": "" } except Exception as e: # 5. 返回错误结果 return { "similarity": "0.0", "status": "failed", "used_algorithm": "", "confidence": "0.0", "error_msg": f"计算失败:{str(e)}" } - 设置函数的输入、输出参数。
输入参数为两个待识别的文本,分别为text1、text2。
输出参数在本次示例代码中,定义在body参数中,因此需要新增一个body参数。返回的JSON体会包含similarity(相似度数值)。
图3 输入参数
图4 输出参数
- 代码配置完成后,单击“确定”完成工具的创建。
- 在“工具列表”页面,单击“调试”按钮,输入参数值,单击“开始调测”检查调测结果。
在本示例中,输入text1、text2文本后,返回的body体中已经包含similarity(相似度数值)。图5 工具调试
- 调试成功后,工具状态随之变为“成功”,此时可单击右上角“发布”,发布插件。
只有经过发布的插件可以给智能体使用。
示例2:网页HTML内容清洗插件
该插件的主要作用是解析和清洗网页HTML内容,该插件主要实现了以下功能。
- 标签过滤:强制移除script(JS脚本),style (CSS样式),meta,iframe (广告/视频),svg等非文本标签。
- 注释移除:删除HTML注释(往往包含无用信息)。
- 安全机制:代码中有一个逻辑if len(tag.get_text()) < 200。只有当这些区域字数很少时才删除。防止误删了被错误标记为class="content-sidebar" 的正文长文。
由于不同的网页HTML内容与样式千差万别,本示例仅作为简单的功能演示使用。正式场景中,一般会对HTML网页样式订制专属的清洗策略。
网页HTML内容清洗插件创建步骤如下:
- 登录AgentArts智能体开发平台,在左侧导航栏“个人空间”区域,选择目标空间。
- 在左侧导航栏中选择“开发中心 > 组件库”,在“插件”页签,单击页面右上角“创建插件”。
- 选择“函数类型”类型的插件,然后根据以下步骤配置插件信息。
表3 基本信息 参数
说明
示例
插件类型
根据实现机制与运行形态的不同,插件分为“API类型”和“函数类型”两种形态。
函数类型
插件图标
单击默认图标按钮,可上传本地图片作为插件的自定义图标。
支持jpg、jpeg、png格式,不超过200KB。
系统默认图标
名称
用于标识当前插件,在“组件库 > 插件”页面会展示该名称。
命名规则:按照插件的实际功能命名,有助于Agent进行插件的精准识别和调度。
命名要求:可以包含中文、英文、数字、下划线;
长度限制:2~64个字符。
网页HTML内容清洗
描述
描述当前插件的类型、功能和适用场景。
需要按照插件的实际功能填写描述,有助于Agent进行插件的精准识别和调度。
解析网页HTML源码,支持智能清洗并提取正文文本。它能自动过滤脚本、样式及广告噪音,将杂乱代码转换为结构化数据。
- 配置完单击“确定”。
平台会自动跳转至工具信息页面,请参考后续步骤创建工具,在创建工具阶段会配置代码脚本、输入、输出参数等信息。
- 在“工具信息”页面,单击“创建工具”,在“添加工具”弹窗单击“新建函数”。
图6 新建函数
- 填写函数名称与描述,执行语言选择“Python3.9”。
表4 函数基本信息 参数
填写示例
名称
WebHtmlParser
描述
解析网页HTML源码,支持智能清洗并提取正文文本。它能自动过滤脚本、样式及广告噪音,将杂乱代码转换为结构化数据。
执行语言
Python3.9
- 单击“编辑源码”,复制如下代码脚本。
图7 编辑源码
本示例中会使用Python的beautifulsoup4依赖包,打包上传方法请参见示例3:创建Python依赖包。
# -*- coding:utf-8 -*- import json import re # 依赖包:beautifulsoup4 (需打包上传) from bs4 import BeautifulSoup, Comment # ===================== 业务逻辑工具函数 ===================== def clean_text(soup): """ 深度清洗 HTML,提取纯净文本 """ for tag in soup(["script", "style", "meta", "head", "input", "iframe", "noscript", "svg", "link"]): tag.extract() for comment in soup.find_all(text=lambda text: isinstance(text, Comment)): comment.extract() for tag in soup.find_all(class_=re.compile(r'(nav|footer|header|sidebar|menu|copyright)', re.I)): if len(tag.get_text()) < 200: tag.extract() text = soup.get_text(separator='\n') lines = [] for line in text.splitlines(): clean_line = line.strip() if clean_line: lines.append(clean_line) return '\n'.join(lines) def extract_links(soup, base_url=""): links = [] seen = set() for a in soup.find_all('a', href=True): href = a['href'].strip() text = a.get_text(strip=True) if not href or href.startswith(('javascript:', '#', 'mailto:', 'tel:')): continue if base_url and not href.startswith(('http', '//')): base_url = base_url.rstrip('/') if href.startswith('/'): href = base_url + href else: href = base_url + '/' + href key = (text, href) if text and key not in seen: links.append({"text": text, "url": href}) seen.add(key) return links def extract_images(soup, base_url=""): images = [] seen = set() for img in soup.find_all('img', src=True): src = img['src'].strip() alt = img.get('alt', '').strip() if base_url and src and not src.startswith(('http', '//', 'data:')): base_url = base_url.rstrip('/') if src.startswith('/'): src = base_url + src else: src = base_url + '/' + src if src and src not in seen: images.append({"alt": alt, "src": src}) seen.add(src) return images # ===================== 平台入口函数 ===================== def main(args: dict) -> dict: """ HTML 内容解析插件入口函数 :param args: 输入参数字典,包含 content、mode、base_url :return: 输出参数字典,包含解析结果 """ try: # 1. 直接从 args 获取输入参数 html_content = str(args.get('content', '') or args.get('html', '')).strip() mode = str(args.get('mode', 'text')).strip().lower() base_url = str(args.get('base_url', '')).strip() # 2. 非空校验 if not html_content: return { "status": "failed", "mode": mode, "result": {}, "error_msg": "未检测到 content 参数,请检查输入" } # 3. 业务处理 soup = BeautifulSoup(html_content, 'html.parser') data = {} if mode == "links": data["links"] = extract_links(soup, base_url) data["count"] = len(data["links"]) elif mode == "images": data["images"] = extract_images(soup, base_url) data["count"] = len(data["images"]) elif mode == "summary": title = soup.title.string if soup.title else "" desc = "" meta = soup.find('meta', attrs={'name': 'description'}) or soup.find('meta', attrs={'property': 'og:description'}) if meta: desc = meta.get('content', '') full_text = clean_text(soup) data["title"] = title.strip() data["description"] = desc.strip() data["summary_text"] = full_text[:800] + "..." if len(full_text) > 800 else full_text else: cleaned = clean_text(soup) data["cleaned_text"] = cleaned data["length"] = len(cleaned) # 4. 直接返回字典 return { "status": "success", "mode": mode, "result": data, "error_msg": "" } except Exception as e: return { "status": "failed", "mode": "", "result": {}, "error_msg": f"处理失败:{str(e)}" } - 设置函数的输入、输出参数。
输入参数为content,类型为string,表示待提取的网页文本。
输出参数在本次示例代码中,定义在body参数中,因此需要新增一个body参数。返回的JSON体会包含清洗后的内容。
图8 输入参数
图9 输出参数
- 添加Python依赖包,本示例中会使用Python的beautifulsoup4依赖包,打包上传方法请参见示例3:创建Python依赖包。
图10 添加依赖包
- 将获取的依赖包上传至平台后,单击“确定”完成工具的创建。
示例3:创建Python依赖包
除了Python3.9、Node.js14.18本身自带的标准库外,其余依赖包均需要手动上传。
本小节结合示例2:网页HTML内容清洗插件作为演示,介绍制作Python的beautifulsoup4依赖包。
- 准备一台Huawei Cloud EulerOS 2.0环境的服务器。
制作函数依赖包推荐在Huawei Cloud EulerOS 2.0环境中进行。 使用其他系统打包可能会因为底层依赖库的原因,运行出问题,比如找不到动态链接库。
本示例中创建一台EulerOS镜像的弹性云服务器进行后续操作的演示(创建一台按需计费、最低规格1u1g、EulerOS镜像的服务器,使用完成即可删除释放)。
- 创建完成后,远程登录至该服务器(可使用弹性云服务器默认的CloudShell方式登录)。
- 依次执行以下命令,下载Python的beautifulsoup4依赖包,并将其压缩为zip包。
# 1. 创建临时目录,用于存放beautifulsoup4依赖包,该依赖包缩写为bs4,创建相同名称的目录 mkdir -p /tmp/bs4 # 2. 安装依赖(自动包含soupsieve) pip install beautifulsoup4 --root /tmp/bs4 # 进入临时目录 cd /tmp/bs4 # 查找 site-packages 路径(Linux 下通用命令) find . -name "site-packages" # 示例输出:./usr/local/lib/python3.9/site-packages # 进入找到的 site-packages 目录(替换为上面步骤中查询的实际路径) cd ./usr/local/lib/python3.9/site-packages # -r:递归打包(包含 bs4、soupsieve 等所有文件);-q:静默模式 # 将包生成到 /tmp 目录,方便后续下载 zip -rq /tmp/bs4.zip *


- 打包完成后即可在tmp路径下查询到bs4.zip文件,下载该依赖包。
图11 下载依赖包
- 返回插件的“添加工具”页面,单击“添加依赖包”。选择“私有依赖包”,按照页面提示前往FunctionGraph创建依赖包。
图12 添加依赖包
- 在FunctionGraph页面,单击“创建依赖包”。在创建依赖包页面填写依赖包名称、选择运行时为Python 3.9,并选择ZIP上传方式。
插件支持Python3.9、Node.js14.18版本的代码,因此运行时也需要选择对应的版本。ZIP上传方式较为便捷,推荐使用。创建依赖包后会自动生成对应的版本号。
图13 创建依赖包
- 返回插件的“添加工具”页面,选择所需的依赖包。
图14 添加依赖包
Python编码规范
本小节主要说明平台支持的Python函数的结构、参数定义及开发规范。开发者需基于此模板编写业务逻辑,实现插件的具体功能。
- 简单场景代码示例:
示例代码:
def main(args: dict) -> dict: """ 运行代码节点会调用此函数,请勿对下面的函数名做修改 :param args: 输入固定为args字典类型,kv为输入参数键值对 :return: 输出参数为字典类型,kv为输出参数键值对 """ ret = { "key0": args.get('input', 'default'), "key1": "hi" } return ret
通过固定的main函数触发代码执行,输入参数 args 是一个字典(dict),包含在界面上配置的所有输入参数,通过args.get('参数名', '默认值')读取。返回值必须与界面上配置的输出参数名称完全一致。
- 复杂场景代码示例:
示例代码:
# -*- coding:utf-8 -*- import json import base64 """ 公共函数使用方法示例 import common headers = {} body = "" data = common.httpRequest("http://localhost:3300/test", headers, body, "POST") if data.get("code") < 300: return data.get("body") return "error: " + data.get("error") 接口返回res = {"headers": {}, "body": string, "code": number, "error": string} """ """" mssiAuthData参数样例 { "header":{}, // 连接器认证header参数 "path": {}, // 连接器认证path参数 "query":{}, // 连接器认证query参数 "body":{}, // 连接器认证body参数 "host":"https://demo.com // API主机地址 } """ def extractRequestParam(rawValue, encoded, defaultValue): if encoded and rawValue: rawValue = str(base64.b64decode(rawValue), "utf-8") return json.loads(rawValue) if rawValue else defaultValue ## 请勿对下面的函数名做修改 def handler(event, context): """ 函数是方法的入口 :param event: 执行事件(event), 包含用户定义的函数参数以及所选择的的连接器认证相关参数 :param context: Runtime提供的函数执行上下文 :return: """ isBase64Encoded = event.get('isBase64Encoded', False) inputData = extractRequestParam(event.get('body'), isBase64Encoded, {}) # 用户定义的函数参数数据 mssiAuthData = extractRequestParam(event.get('mssiAuthData'), isBase64Encoded, {}) # 连接器认证数据 mssiAuthData["securityToken"] = context.getToken() dataExtendConfig = extractRequestParam(event.get('dataExtendConfig'), isBase64Encoded, {}) # 流步骤扩展参数 result = {} return json.dumps(result)
代码主要包含三个部分:
- 公共库引用说明:代码顶部的注释展示了如何使用平台内置的common库发起HTTP请求。
- 辅助工具函数:extractRequestParam用于处理参数的解包与格式转换。
- 主入口函数:handler(event, context)是插件执行的核心,包含业务逻辑。
主入口函数:
def handler(event, context): # ...- 约束:请勿修改函数名handler。平台通过此名称定位并执行函数。
- 参数:
- event (Dict):包含本次调用的所有输入数据。
- context (Object):运行时上下文对象,提供系统级能力。
输入参数:
event对象中包含了经过Base64编码的原始数据。模板代码通过extractRequestParam函数自动完成了解码和JSON反序列化,开发者可直接使用以下变量:
表5 变量说明 变量名
含义
用途
inputData
用户业务参数
对应插件定义中用户填写的入参(如查询关键词、日期等)。
mssiAuthData
连接器鉴权数据
包含调用第三方API所需的host,header等鉴权信息(由平台连接器配置自动注入)。
dataExtendConfig
扩展配置
流程步骤中的高级配置参数(通常用于低代码编排场景)。
代码示例 # 获取用户输入的 "city" 参数 city_name = inputData.get("city", "city_name") # 获取连接器配置的主机地址 api_host = mssiAuthData.get("host")上下文与安全凭证:
context提供与运行环境交互的能力。
context.getToken():获取当前执行环境的安全令牌(Security Token)。
用法:模板代码已自动将Token注入到mssiAuthData["securityToken"]中,通常用于身份验证。
发起网络请求:
平台预置了common模块用于处理网络请求。请勿使用Python原生requests库,建议使用common.httpRequest以确保兼容性和安全性。
入参:
- url (str):请求完整地址。
- headers (dict):请求头。
- body (str/json):请求体。
- method (str):请求方法("GET", "POST", etc.)。
返回值(data) 结构:
{ "code": 200, # HTTP 状态码 "body": "...", # 响应体字符串 "headers": {...}, # 响应头 "error": "..." # 错误信息(如有) }返回值规范:
函数最终必须返回一个JSON格式的字符串。
代码示例 result = { "status": "success", "message": "查询成功", "data": { "temperature": 25 } } return json.dumps(result, ensure_ascii=False)
Node.js编码规范
本小节主要说明平台支持的Node.js函数的结构、参数定义及开发规范。开发者需基于此模板编写业务逻辑,实现插件的具体功能。
- 简单场景代码示例:
示例代码:
/** * 运行代码节点会调用此函数,请勿对下面的函数名做修改 * @param {Object} args - 输入固定为args对象类型,kv为输入参数键值对 * @returns {Promise<Object>} 输出参数为Promise包裹的对象类型,kv为输出参数键值对 */ exports.main = async (args) => { const ret = { "key0": args?.input ?? 'default', "key1": "hi" }; return ret; }
平台通过固定的exports.main异步函数触发代码执行。输入参数args是一个对象(Object),包含在界面上配置的所有输入参数,通过可选链操作符?.和空值合并操作符??读取(如args?.input ?? 'default')。返回值必须与界面上配置的输出参数名称完全一致。
- 复杂场景代码示例:
示例代码:
/** * common是平台提供的公共函数,包括方法有post和get请求 * * const common = require("./common.js"); * const headers = {}; * const body = ""; * 示例1:异步调用 * common.httpRequest("http://localhost:8080/test", headers, body, "POST").then((data) => { * if(data.code < 300){ * return data.body; * } * return {}; * }); * * 示例2:同步调用 * const data = await common.httpRequest("http://localhost:8080/test", headers, body, "POST"); * if(data.code < 300){ * return data.body; * } * return {}; * 接口返回 data = { * "headers": {}, * "body": string, * "code": number, * "error": string * } */ /** * * mssiAuthData参数样例 * { * "header":{}, // 连接器认证header参数 * "path": {}, // 连接器认证path参数 * "query":{}, // 连接器认证query参数 * "body":{}, // 连接器认证body参数 * "host":"https://demo.com // API主机地址 * } * */ function extractEventData(event, name) { let data = event[name] if (event.isBase64Encoded && data) { data = new Buffer(data, 'base64').toString() } return data ? JSON.parse(data) : {} } /** * 函数是方法的入口 * @param {*} event 执行事件(event), 包含用户定义的函数参数以及所选择的的连接器认证相关参数 * @param {*} context Runtime提供的函数执行上下文 * @returns */ exports.handler = async function (event, context) { const inputData = extractEventData(event, 'body') // 用户定义的函数参数数据 const mssiAuthData = extractEventData(event, 'mssiAuthData') // 连接器认证数据 mssiAuthData.securityToken = context.getToken() const dataExtendConfig = extractEventData(event, 'dataExtendConfig') // 流步骤扩展参数 let result = "{}"; return result; }
代码采用CommonJS规范,主要包含以下部分:
- 依赖引入:通过require("./common.js") 引入平台内置的HTTP请求库。
- 辅助工具:extractEventData函数用于自动处理Base64解码与JSON反序列化,开发者通常无需修改此函数。
- 主入口:exports.handler是异步函数入口,承载核心业务逻辑。
主入口函数:
exports.handler = async function (event, context) { // 业务逻辑区域 }- 约束:必须保留exports.handler命名。
- 特性:函数被定义为async,您可以在函数体内使用await语法来处理异步操作(如网络请求)。
输入参数:
代码模板通过extractEventData帮助您从event中提取并格式化了以下关键对象,您可以直接在handler中使用:
表6 变量说明 变量名
类型
含义
用途
inputData
Object
用户业务参数
对应插件定义中用户填写的入参。
mssiAuthData
Object
连接器鉴权数据
包含调用第三方API所需的host, header, query等鉴权配置信息。
dataExtendConfig
Object
扩展配置
流程编排中的高级配置参数。
代码示例 // 获取用户输入的参数 "keyword" const keyword = inputData.keyword || "default"; // 获取连接器配置的主机地址 const apiHost = mssiAuthData.host;
上下文与安全凭证:
context对象提供运行时的系统能力。
- context.getToken():获取当前执行环境的安全令牌(Security Token)。
- 自动注入:模板代码已执行mssiAuthData.securityToken = context.getToken(),将令牌自动合并到鉴权数据中,方便后续调用使用。
发起网络请求:
平台提供了common模块用于发送HTTP请求。为了代码的可读性和维护性,强烈建议使用await方式(同步写法)进行调用。
接口定义 const common = require("./common.js"); // ... const response = await common.httpRequest(url, headers, body, method);响应结构 { "code": 200, // HTTP 状态码 (Number) "body": "...", // 响应体 (String),通常需要 JSON.parse 解析 "headers": {}, // 响应头 (Object) "error": "..." // 错误描述 (String) }