低代码平台中的数据连接方式(上)

语言: CN / TW / HK

1. 前言

在早几年,“拖拽式 H5 营销页制作工具” 曾经是前端界的一大热门方向,这类工具的特点是可以通过拖拽的方式来生成带有各种酷炫效果的静态营销页,这类工具可以看作是现今“低代码平台”的前代产品。

而在当今的互联网中,以 “静态” 方式承载内容的页面越来越少。也就是说,“拖拽生成静态页”这样单纯的能力在现代应用的开发过程中能覆盖的场景是非常少的,这就催生了以 “能够对接动态数据” 为特征的第二代低代码产品。

为了满足 “对接动态数据” 这一基础诉求,低代码平台经历了从最初简单 API 对接模式到完整的数据模型接管的发展过程,而完整的数据模型接管能力,也是现今各低代码厂商发力深耕的方向之一。

低代码平台中可选的数据连接方式有很多种,各种方法产生和成熟的时期不同。而在现今互联网主流的业务模式下,这些方法在不同的场景下都有其适用的范畴。

关于低代码平台的数据链接方式这个话题,我们将分为上下两篇内容进行分享:

  • 在(上)篇中,我们将介绍 经典的单 API 通信数据连接方式 - 简单的单 API 连接方式存在的问题 - 相应解决方案

  • 在(下)篇中,我们将介绍在低代码时代发展起来的 API 编排 - FaaS - 数据库直连等新型方案

2. 传统手工模式下动态数据的获取和渲染

在互联网页面开发中,动态数据的获取 - 渲染可以说是一个最基本的 “需求”。在多数情况下,当浏览器向服务端请求一个页面的时候,服务端返回的会是一个页面的 “框架”,而页面的具体内容会由页面中的 JavaScript 脚本向服务端发起 ajax 请求并将返回结果渲染到页面上。

在 jQuery 盛行时期的互联网开发中,“从服务端获取数据并渲染到页面上” 的代码可能是这样的(代码示例来源:jQuery官网, https://api.jquery.com/jquery.ajax/):

var menuId = $( "ul.nav" ).first().attr( "id" );
var request = $.ajax({
url: "script.php",
method: "POST",
data: { id : menuId },
dataType: "html"
});


request.done(function( msg ) {
$( "#log" ).html( msg );
});


request.fail(function( jqXHR, textStatus ) {
alert( "Request failed: " + textStatus );
});

而在 MVVM 框架经过数年角逐并形成 React / Vue 二分天下之势力的当今互联网开发中,“从服务端获取一段数据并在页面中渲染出来” 的代码可能是这样(React,代码示例来源:https://dev.to/antdp425/react-fetch-data-from-api-with-useeffect-27le)

// 1. Import *useState* and *useEffect*
import React, {useState, useEffect} from 'react';
import './App.css';


function App() {
// 2. Create our *dogImage* variable as well as the *setDogImage* function via useState
// We're setting the default value of dogImage to null, so that while we wait for the
// fetch to complete, we dont attempt to render the image
let [dogImage, setDogImage] = useState(null)


// 3. Create out useEffect function
useEffect(() => {
fetch("https://dog.ceo/api/breeds/image/random")
.then(response => response.json())
// 4. Setting *dogImage* to the image url that we received from the response above
.then(data => setDogImage(data.message))
},[])


return (
<div className="App">
{/* 5. Using *dogImage as* the *src* for our image*/}
{dogImage && <img src={dogImage}></img>}
</div>
);
}


export default App;

或这样(Vue,代码示例来源:https://cn.vuejs.org/v2/cookbook/using-axios-to-consume-apis.html)

new Vue({
el: '#app',
data () {
return {
info: null
}
},
mounted () {
axios
.get('https://api.coindesk.com/v1/bpi/currentprice.json')
.then(response => (this.info = response))
}
})

无论是早期 jQuery 还是现今已经成为互联网页面基础设施的 MVVM 框架,“动态数据连接” 的方式大抵是 “向某个后端接口发送请求然后等待数据返回”。

而在进行前端业务组件的 “低代码” 形式封装时,低代码框架和平台的建设者们第一步做的通常也是将组件需要的 API 请求抽取成配置项。

3. 低代码最初的数据连接方式 

—— 通过 API URL 进行数据通信

如图 1 中的 CRUD 组件,在组件配置中填写数据列表的获取接口和新增数据提交接口后,组件初始化时会向填写的 API 发起网络请求,新增记录时也会使用配置的新增数据提交接口。

这样一来,通过一个简单的配置项就能够实现原本需要书写大段代码的功能。

图 1  为 CRUD 组件配置异步请求接口

这种通过 API 配置即可实现数据连接的方案,很简单也很美好,在低代码平台建设的初期往往也会被作为 “最小可用版本” 的首选方案。

但是在实际落地场景中,这种最简单的方案往往会遇到两个问题:

    • 一是前端需要的数据格式和后端返回的数据格式不匹配的问题。

    • 二是前端最经典的问题 —— 跨域问题。

下面我们结合低代码平台在实际落地中的场景来看一看上述两个问题的产生缘由。

4. 问题产生 —— 低代码平台实际落地中的阻碍

    4.1 前后端数据格式不匹配问题

在低代码平台实际业务落地的过程中,多数时候面对的场景都不是 “从零开始” 用低代码平台去搭建一个应用,而是 “将某些业务模块逐步迁移到低代码平台”。这就意味着低代码平台需要和许多已经在线上运行的旧接口打交道。

在业务逐步往低代码迁移的过程中,很长一段时间内可能是如图 2 所示的状态 —— 低代码平台需要去连接一些仍在支持线上业务的接口,同时这些接口也仍在支撑着运行中的线上业务,这就意味着不能为了 “接入低代码平台” 而贸然对这些接口进行改造。

图 2  低代码平台连接现有的旧接口

而从低代码平台中的角度来说,通用组件为了保证其通用性,必然需要对接口返回的数据格式有一个统一的规约。例如在 低代码平台爱速搭 的组件体系(即 AMIS)中,就规定了数据接口的返回格式需要符合以下格式,可以参考一下链接:

https://aisuda.bce.baidu.com/amis/zh-CN/docs/types/api

{
"status":0,
"msg":"",
"data":{
...其他字段
}
}

而正如前文所说,低代码平台很多时候需要去连接旧的线上接口,这些接口返回的数据格式往往不符合低代码平台的要求,并不太可能 “为了适配低代码平台” 而去进行专门改造。

那么除了为低代码平台定制开发一套专用接口外,有没有办法能够既享受低代码平台带来的便利,又能减免后端接口的改造成本呢?

这个问题我们将在本篇的第 5 到第 7 节做统一解答。我们先来看一看另一个前端经典问题 —— 跨域问题的产生。

    4.2 跨域问题

如前文的图 2 所示,当前线上业务的域名是 a.xxx.com ,而低代码平台的域名是 b.xxx.com,这意味着旧的线上接口可能无法被来自 a.xxx.com 的前端请求直接访问,而如果要求后端改造现有接口或服务器配置来多兼容一个域名,也可能导致不可控的成本和安全隐患。

“跨域问题” 的实际效果如图 3(图片来自百度搜索),前端开发人员都非常熟悉的 blocked by CORS policy 报错。

图 3  前端向不同域名发送的请求由于跨域被浏览器拦截

为此,低代码平台爱速搭提供了“浏览器端的数据映射机制”、“浏览器端请求/接收适配器”和“ API 代理”等几项能力来协作解决第 4 节提到的这两个问题。

借助这些能力,可以在后端接口不做任何改动的情况下实现低代码平台对业务的平滑接入。

5. 浏览器端的数据映射机制

数据映射,指的是在接口发送 / 接收前将原始字段的值赋给目标字段,例如后端返回的格式是 {a: 'xxx', b: 'ooo'} 而前端组件需要的格式是  {c: 'xxx', b: 'xxx'},在数据映射中配置 c: ${a} 就可以将接口返回的数据格式化成前端需要的格式。

在爱速搭中,数据映射分为浏览器端数据映射和服务端数据映射。关于服务端数据映射,我们会在本文的 7.2 节予以说明。

浏览器端数据映射在爱速搭中的配置界面如图 4 所示,可以在面板上打开 “数据映射” 开关并以 key: value 的格式进行数据映射配置。

图 4  用数据映射解决数据格式匹配问题

需要注意的是这个 “映射” 是在数据接口请求发送之前 / 返回之后在浏览器端进行的格式化,所以设置之后观察接口返回数据也不会看到任何改变。

该能力是在 AMIS 框架中实现的,爱速搭对其进行了可视化封装,关于 AMIS 框架中的实现,可以阅读官方文档:

https://aisuda.bce.baidu.com/amis/zh-CN/docs/concepts/data-mapping

6. 浏览器端请求 / 接收适配器

在简单的映射无法满足复杂的数据格式化需求时,爱速搭还提供了通过 js 函数来对数据格式进行处理的方式。

如图 5,可以在 CRUD 组件的 API 配置处编写 js 函数代码,在请求发送 / 请求结果返回时,这些自定义函数会被调用来对数据进行格式化,这个 “格式化” 的过程也是在浏览器端执行的。

图 5  在爱速搭平台 中编写适配器函数

该能力同样是在 AMIS 框架中实现的,具体见 AMIS 文档:

https://aisuda.bce.baidu.com/amis/zh-CN/docs/types/api#%E9%85%8D%E7%BD%AE%E8%AF%B7%E6%B1%82%E9%80%82%E9%85%8D%E5%99%A8

7. API 代理

跨域问题产生的根本原因是浏览器对跨域访问的限制 。在低代码平台实际落地的场景中,低代码平台和业务往往部署在不同的域名下,并且业务方也通常不可能为了接入低代码平台而增加额外的跨域访问白名单或独立部署一套同域下的低代码平台。故而 “跨域问题” 也是低代码平台落地的一大阻碍。

    7.1 统一 API 代理方案

处理跨域问题的方案有很多种,爱速搭采用了统一 API 代理的方案,通过后端的代理服务来对 API 请求进行统一转发,从而规避了跨域请求被浏览器拦截的问题。

下面我们来看一看爱速搭中 API 代理服务的具体实现。

在爱速搭中,默认情况下组件中填写的接口配置在不是由前端直接向服务端发起请求,而是经由爱速搭的 API 代理服务进行转发后再将实际后端接口返回的数据通过代理服务返回到前端。

如图 6,在 Form 组件上配置了一个保存接口的 url。

图 6  Form 组件上配置的保存接口 url

实际发起请求时访问的 url 如图 7:

图 7  实际发起请求时通过 Proxy 接口

从原理上说,爱速搭 API 代理的运行方式是在编辑保存阶段将页面中的 API 抽出来存到一个数据库表中,并给每个 API 生成一个标识,然后在运行时实际访问的是类似  api/proxy/:apiId 这样的接口,再由后端服务通过 apiId 找到实际的接口 url,转发请求并等待远端返回后再将结果返给前端。API 代理在当前市面上的低代码平台中是一个 “标配” 服务。

跨域问题只存在于前端浏览器层面,这种通过后端接口转发请求的方式,从根本上规避了前端跨域问题的产生

    7.2 后端数据映射及后端请求 / 接收适配器

除了简单的转发,爱速搭的 API 代理还提供了后端执行的数据映射和适配器等机制。在应用设置 - 接口 - 全局接口适配器中可以为 API 代理配置全局适配器,如图 8 所示:

图 8  全局适配器

而在爱速搭中如果希望为单个 API 配置映射和适配器,可以 API 中心新建单个接口并填写相应配置项,如图9所示:

图 9  为单个接口配置设置参数转换和适配器

为什么有了服务端执行的数据映射和请求 / 接收适配器,还需要前面所说的浏览器端执行方案呢?

原因有两点:

  • AMIS 作为一个开源项目,在许多时候可能会被作为独立依赖引入到项目中,在没有 API 代理机制的情况下前端方案可以解决一部分问题。

  • 如果在配置项中指定请求为 raw: 则网络请求不会经过 API 代理发送,这时如果需要对数据进行格式化,则需要借助前端方案。

此外,爱速搭还开放了自定义 header 等请求信息的配置能力,由于篇幅所限,本文不再一一赘述,有兴趣的读者可自行查阅爱速搭或 AMIS 官方文档。

8. 小结

通过上述几个方案,爱速搭解决了低代码平台在实际落地时的改造成本和沟通成本问题,使得业务不再需要为了享受低代码平台的便利而进行可能带来更多麻烦的改造工作。

但基于单 API 通信的方案仍然依赖于 “现成” 的接口。如果是全新的功能,依旧需要由后端开发人员以传统模式进行 API 的开发和部署上线 —— 当然,并不能武断地认为这种方案就应当被淘汰,因为在实际生产环境中,许多通用型的接口已经作为稳定的数字资产被沉淀下来,作为open api 提供给业务方使用,以 API 方式来调用这些通用接口,显然最合适不过。

那么在后端接口也 “不存在” 的情况下,有没有办法能够通过低代码平台快速开发上线应用呢?答案是肯定的。为此爱速搭平台提供了 API 编排,FaaS 和数据库直连方案,我们将在本文的(下)篇中介绍这些新型的技术方案。

  往期推荐  

:link:

可视化神器背后的奥秘

6000字,详解数据仓库明星产品背后的技术奥秘

“智感超清”之HDR技术落地实践