Skip to main content

业务连接器

1 引言

业务连接器主要是我们共工对接外部数据已经存在的接口数据

连接器管理里面有创建连接器分组,这个主要是为了维护各种业务类型进行分类的一个文件夹管理。

在某个组下面创建连接器 先选中需要的文件组、接口协议类型(socket 类型参考业务连接器 socket 支持),然后创建接口

以下为接口的所有配置项。

2 接入业务连接器

2.1 操作步骤

配置 接口名,请求路径,寻址信息 ----> 调试,适配数据

2.1.1 配置项介绍

配置项名称(红色为必填项)说明Key(用于数据源插件)
接口编码作为数据源内的接口标识,由平台自动生成,不允许修改。-
接口名(英文)用户自定义的接口标识,默认会加上 数据源编码 作为前缀。 当两个数据源需要复用相同的接口时,就可以通过接口名选择导入。-
接口描述用户自定义的说明性文案,仅用于展示-
是否 Mock 数据开启后允许用户输入静态的模拟数据,不会发起真正的 HTTP 请求。在用户接口没有就绪时使用。isMock
请求路径接口的请求地址,包含请求方式,post 和 get 两种请求方式不包含域名(或 IP:Port),不包含 QUERY 参数。
例: 假设接口为 http://127.0.0.1:8888/getUser?id=xxx,那么请求路径是/getUser
url
寻址信息“域名” 或 “IP:PORT”,某些特殊的部署版会有其他寻址类型。
例: 假设接口为 http://127.0.0.1:8888/getUser?id=xxx,那么寻址信息是 127.0.0.1:8888
service
超时时间(ms)指平台的服务器请求用户接口的最长等待时间,当用户接口超过时间没有回包,会返回 Timeout 的错误。默认 3s。timeout

2.1.2 Mock 数据

操作路径: 开启 Mock > 创建场景 > 编写 JSON > 调试 > 查看“请求结果”

1.开启 mock

2.新增场景

3.编写 json 格式的 mock 数据

4.调试

备注:可以使用接口请求结果作为 mock 数据 点击设置为 Mock 数据之后 mock 设置里面多出一条数据里面就是请求结果的数据

2.1.3 参数调试

参数调试用来帮助接口调试,是一种 mock 行为。点击接口调试的“调试”按钮,接口的 HTTP query、HTTP body、HTTP request header 就会发送。支持 JSON 和 FormData 两种方式。

JSON 方式,将 http 的 query、body、request header 以 JSON 的方式去设置,也暗含着这个连接器接口的 Request header 的 Content-Typeapplication/json。 例如,将一个连接器接口的 query 字段设置如下:

FormData 方式,连接器接口应接受 FormData 数据格式,这个连接器接口的 Request header 的 Content-Typemultipart/form-data;charset=UTF-8

参数头指 HTTP request header,将在共工触发连接器的接口 request header 上设置。

参数内容为 HTTP body,会以 FormData 数据格式在共工触发连接器的接口 request body 上设置。

例如,一个接口接收两个字段,fileType 和 file。其中 fileType 为普通文本字段,file 为文件类型,用户可自行上传文件:

3 其他配置案例

存在部分特殊的接口,静态的配置信息可能无法满足接口调用的需求,因此需要依赖 前置插件 的能力,实现业务接口个性化的逻辑配置。

常见的特殊逻辑

Restful 请求方法,如 PATCH /user/:userId,动态路径:如 GET /user/:userId

如下图:里面的 list 需要传一些分页信息,参数需要修改

3.1 接口适配

为什么要适配数据?

1.存在的用户接口可能不满足共工数据通信协议的约定,隐藏需要适配,调整用户接口的输入和输出,以满足共工数据通信协议的规范

2.部分特殊的调用参数和响应数据必须在插件里面处理,比如鉴权信息、敏感数据

数据源通常包含六个接口(除了 只读数据源单接口数据源

  • 只读数据源 仅包含 `list` `count` `get` 接口,没有写相关的接口
  • 单接口数据源 无约定功能,不需要通信协议
接口 Code功能
list获取多条数据、并且返回数据的总数(可选)
count获取数据的总数,用于展示时的分页计算
get获取单条数据
crate创建一条数据
update修改一条数据
delete删除单条数据

3.2 运行流程

一个连接器接口的执行,大致是一个 pipeline 的过程,下面的流程图详细介绍了各个步骤。

3.2.1 参数修剪

返回值作为新的'调用参数',传递给后续流程

query 对象下的每个字段都是字符串类型,因为是通过 `url` 传送的。body 对象只有在 `POST` 请求时才有,数据类型比较友好。context上下文
({query, body, header}, context) => {
// context 上下文内有当前环境的 header
// query, body, header 为接口的原始入参
// 此处的返回值会作为这个接口的最终入参
// 调试时,原始入参来自“参数调试”配置
// 运行调用时,原始入参来自页面编辑器配置

/**
* return {
* query: { // query 改写 pagesize 为 pageSize
* ...query,
* pageSize: query.pagesize
* },
* // body 不保留
* header: { // header 只设置 Authorization
* Authorization: '12345'
* }
* }
*/

return {
query,
body,
header: {
...header,
Authorization: context?.header?.Authorization
}
}
}

3.2.2 响应修剪

返回值作为新的'响应数据',传递给后续流程

respose:数据源接口的响应体context:上下文备注:共工里面的数据结构 total--总数;totalPage--总页数;actionResult--所有数据;这里的数据不符合共工协议的数据,所以需要通过响应修剪成我们需要的数据。
(response) => {
// response为接口的原始返回值
// 此处的返回值会作为该接口的返回值

/**共工集合类组件修剪
* 当前集合类组件,接收 actionResult,表示返回的数据列表。接收 total,表示数据总量,用于分页
* 原始 API response 假如为:
* {
* code: 200,
* data: {
* totalSize: 15,
* data: [...]
* }
* }
* response 应该被修剪为:
* return {
* total: response?.data?.totalSize,
* actionResult: response?.data?.data
* }
*/

/**共工报错修剪
* 接收 code 表示接口是否成功,接收 successMessage(string) 表示接口返回成功提示消息,接收 errorMessage(string) 表示接口返回失败提示消息
* 如果 code 为 200,显示含 successMessage 的消息提示。如果 successMessage 不存在,提示默认消息或不提示
* 如果 code 不为 200,显示含 errorMessage 的消息提示。如果 errorMessage 不存在,提示默认消息或不提示
* 原始 API response 假如为:
* {
* code: 1,
* success: true,
* msg: '执行成功',
* data: {...}
* }
* 或
* {
* code: 500,
* success: false,
* msg: '保存失败'
* }
* response 可被修剪为:
* return {
* code: response?.code == 1 ? 200 : 500,
* successMessage: '保存成功自定义提示',
* errorMessage: '保存失败自定义提示'
* }
*/

return {
total: response.data.totalSize,
totalPage: response.data.totalSize,
actionResult: response.data.data
}
}

3.2.3 插件使用

插件在连接器接口中的触发位置参照“运行流程”。

一个插件就是一个 JavaScript 函数。共工为插件提供了 utils 函数,可在插件中调用。下面的代码是新建一个插件后的默认插件代码:

async ({prevData, utils}) => {
// 插件添加到连接器接口中,连接器接口执行步骤:调试参数/组件入参 -> 参数修剪 -> 前置插件 -> 发送api -> 后置插件 -> 响应修剪 -> 调试接收/组件接收
// 该插件接收prevData 和 utils,返回自定义
/**
* prevData来自上一个步骤的返回,可打印查看详情
* 如果为前置插件,应包含如下字段:
* query: Object; // http query
* body: Object; // http body
* header: Object; // http request header
* 如果为后置插件,应包含如下字段:
* requestBody: string; // 业务api返回的请求体
* requestHeader: Object; // 业务api返回的请求头
* requestMethod: string; // 业务api返回的请求方法
* requestUrl: string; // 业务api返回的请求地址
* responseBody: string; // 业务api返回的响应体
* responseHeader: Object; // 业务api返回的响应头
* responseStatusCode: number; // 业务api返回的响应状态码
* response: ; // 业务api返回的响应体被JSON解析:JSON.parse(responseBody)
* requestInfo: Object; // 业务api请求的payload:env(调试环境)、apiInfoId、httpApiCode、query、body、header
* utils为共工提供的工具函数:
* triggerHttpApi(apiParam) 调用连接器接口执行api,apiParam和prevData.requestInfo一致,返回api调用结果
* triggerHttpApiWithStep(connectorCode, apiCode, query, body, header) 调用连接器接口执行api,包括接口的参数修剪、响应修剪、插件的步骤。返回插件和修剪处理过的api调用结果
* getContextAuthorization() 返回共工的http request authorization
**

return prevData;
}

3.2.4 接口调试

这里可以返回出接口的请求接口,请求信息,接口响应,原始响应。

例子 1:参数修剪中打印 query 的内容

1.开启参数修改,编写逻辑 这里需要加分页参数

{
"query": {},
"body": {
"pageSize": 20,
"pageNum": 1
},
"header": {}
}

2.点击调试按钮 可以看到请求的结果

3.第一次获取到调试结果需要更新结果,生成实体,点击查看结构可以看到数据的返回结构

4.定义实体 根据返回的数据结构 我们选择接到作为该数据源的实体

5.查看实体 在该实体下我们可以进行字段的增删改查的操作

例子 2:鉴权接口的配置

接口通常需要鉴权,鉴权对业务接口都是通用的,因此可以在插件中实现鉴权。分两种情况:

  • 鉴权在共工体系内

    • 共工为插件提供了工具函数 utils.getContextAuthorization() ,它返回共工体系内的 Authorization(HTTP request header Authorization),值类似 bearer 882d8026-86aa-4dd6-9306-ae0c1054ff09。我们可以为获取 Authorization 写一个插件,将 Authorization 添加到业务 api 上:
async ({prevData, utils}) => {
// 前置登录插件,添加在业务api的前置插件处,连接器接口执行步骤:调试参数/组件入参 -> 参数修剪 -> 其他前置插件 -> *这个前置插件* -> 其他前置插件 -> 发送api -> 后置插件 -> 响应修剪 -> 调试接收/组件接收
// 接收prevData 和 utils
// prevData来自上一个步骤的返回,应包含如下内容,可打印查看详情
// query: Object; // http query
// body: Object; // http body
// header: Object; // http request header
// 用utils.getContextHeader 获取共工的Authorization,设置到业务api的header上

return {
...prevData,
header: {
...prevData.header,
Authorization: utils.getContextAuthorization()
}
};
}
  • (不推荐)共工为参数修剪提供了 context,Authorization 可通过 context?.header?.Authorization 获取,因此也可在参数修剪里将 Authorization 添加到业务 api 上:
({query, body, header}, context) => {

return {
query,
body,
header: {
...header,
Authorization: context?.header?.Authorization
}
}
}
  • 鉴权在第三方

一个鉴权的场景,登录接口接收 userName 和 passwd,登录成功返回 token。业务 api 接口 request header 中需要添加这个 token,才能返回数据,否则报错。

大致思路为,为业务接口设置一个前置插件,和一个后置插件。前置插件先到浏览器缓存 localStorage 中查找 token,如果找到,就把 token 设置到业务接口上。如果找不到,说明没有登录过,就要去发登录接口获取 token(并且把 token 存储到 localStorage 中)。

如果缓存中获取的 token 不对怎么办?也就是业务接口拿着一个错误的 token 去发送,必然报错。因此要加一个后置插件,后置插件中判断,如果业务接口报登录失效,再去发登录接口,拿到正确的 token,再用新 token 触发业务接口,将结果返回。

考虑一个问题:如果一个页面有多个连接器,第一次进去页面,都要登录,怎么办?难道一个页面在 1s 内多次登录吗?可以考虑在前置插件和后置插件里加一个互斥锁,保证一个页面最多只有一次登录,就能拿到 token。互斥锁可以存储在 sessionStorage 中。具体太复杂,不展开。

async ({prevData, utils}) => {
// 前置登录插件,添加在业务api的前置插件处,连接器接口执行步骤:调试参数/组件入参 -> 参数修剪 -> 其他前置插件 -> *这个前置插件* -> 其他前置插件 -> 发送api -> 后置插件 -> 响应修剪 -> 调试接收/组件接收
// 接收prevData 和 utils
// prevData来自上一个步骤的返回,应包含如下内容,可打印查看详情
// query: Object; // http query
// body: Object; // http body
// header: Object; // http request header
// 如果缓存有token(无法判断token是否有效),认为有效,并直接返回prevData
// 如果缓存没有token,说明从来没有登录过,先发登录的连接器接口,拿到新token,缓存,更新prevData.header.token,再返回prevData
console.log('plugin preLogin enter.. ',prevData, utils);
// 这个登录插件仅调用登录api,获取到token后存入localStorage里。业务
let token = window.localStorage.getItem('deviceaiToken');
console.log('plugin preLogin get token from ls ',token);

if (token) { // 如果缓存有token(无法判断token是否有效),认为有效,并直接返回prevData
prevData.header.token = token;
return prevData;
}

const res = await utils.triggerHttpApiWithStep('login', 'request', {}, {userName: 'admin', passwd: 'admin123456'}, {});
console.log('plugin preLogin login res: ',res);

if (res?.code == 200 && res?.data?.token) { // 登录成功
console.log('plugin preLogin login success with new token: ',res?.data?.token);
token = res?.data?.token;
// 拿到新token,缓存,更新prevData.header.token
window.localStorage.setItem('deviceaiToken', token);
prevData.header.token = token;
} else { // 登录失败
// 用户想做什么自己加代码
}

// 返回prevData
return prevData;
}
async ({prevData, utils}) => {
// 后置登录插件,添加在业务api的第一个后置插件处, 连接器接口执行步骤:调试参数/组件入参 -> 参数修剪 -> 前置插件 -> 发送api -> *这个后置插件* -> 其他后置插件 -> 响应修剪 -> 调试接收/组件接收
// 接收prevData 和 utils
// prevData 包含如下内容,可打印查看详情
// requestBody: string; // 业务api返回的请求体
// requestHeader: Object; // 业务api返回的请求头
// requestMethod: string; // 业务api返回的请求方法
// requestUrl: string; // 业务api返回的请求地址
// responseBody: string; // 业务api返回的响应体
// responseHeader: Object; // 业务api返回的响应头
// responseStatusCode: number; // 业务api返回的响应状态码
// response: ; // 业务api返回的响应体JSON解析 ****** JSON.parse(responseBody)
// requestInfo: ; // 业务api请求payload ****** env(调试环境)、apiInfoId、httpApiCode、query、body、header
// 业务api如果返回正常数据,直接返回 prevData.response
// 业务api如果报session失效,应再次登录,拿到新token。用新token再去调用一次业务api。最终返回和prevData.response一样的数据内容
console.log('plugin postLogin enter..', prevData, utils);

if (prevData?.response?.code === -1) { // 业务api报session失效,即token无效
console.log('plugin postLogin session failed');
let token;
// 再次登录
const res = await utils.triggerHttpApiWithStep('login', 'request', {}, {userName: 'admin', passwd: 'admin123456'}, {});

if (res?.code == 200 && res?.data?.token) { // 登录成功,拿到新token
console.log('plugin postLogin login success with new token: ',res?.data?.token);
token = res?.data?.token;
window.localStorage.setItem('deviceaiToken', token); // 缓存后其他api也能用到

// 再次发业务api,返回内容应和 prevData?.response 一样
const [err, apiRes] = await utils.triggerHttpApi({
...prevData?.requestInfo,
header: {
...prevData?.requestInfo?.header,
token
}
});

console.log('plugin postLogin send api with new token: ',err, apiRes);

if (!err) {
return JSON.parse(apiRes?.responseBody);
}
} else { // 登录失败
// 用户想做什么自己加代码
console.log('plugin postLogin login failed: ',res);
}
} else { // 业务api如果返回正常数据,直接返回 prevData.response
console.log('plugin postLogin normal return');
return prevData?.response;
}
}