设计
- 文章作者: flytreeleft - flytreeleft@crazydan.org
- 文章链接: https://duzhou.crazydan.io/docs/development/framework/server/gateway/design
- 版权声明: 本文章采用许可协议《署名 4.0 国际 (CC BY 4.0)》。 转载或商用请注明来自渡舟平台!
- 控制外部请求的守门人
- 对用户进行认证,对操作进行鉴权,通过状态机驱动资源访问
- 动态生成用户的 Web 端页面,并通过 Nop Xpl 生成
index.html
以便于注入真实的平台名称
、平台 Logo
、等待动画
等定制内容- 通过 Nop 的
precompile
机制,调用npm
对页面渲染引擎进行构建, 并将构建产物复制到src/main/resources/META-INF/resources
目录下
- 通过 Nop 的
- 拆分为
api
和web
两类网关以独立进行开发,并可按需引入
状态机驱动
根据各类状态数据来驱动系统的业务逻辑流转,并提供对状态机的可视化设计支持。
- 在多租户模式下,以多租户标识为 Delta 层,再在该层内定制状态驱动 DSL
- 采用 Nop Task 机制进行实现
上下文
资源访问
前端站点(
site
)也属于资源(resource
)。
该状态机用于控制所有的资源访问动作,其流转过程中由 用户登录状态(是否登录)和 资源可访问状态(是否存在、用户是否有权限)确定后续逻辑, 并通过 链接跳转 驱动该状态机(没有链接跳转就无法驱动状态变化)。
接口调用返回状态码和 JSON 响应数据,在响应数据中会包含错误码、错误信息、跳转地址等, 由前端根据状态码和响应数据判断后续操作。
对前端站点 url 的请求返回的都是页面渲染引擎代码, 其具体的页面结构需单独再发送一次资源请求才能获取到, 所以,以上状态机控制的是资源请求接口,对 js、css 等静态资源不做控制。
API 网关
- 在页面设计时,在引用的 API 中需以参数或 Header 形式附加目标服务标识, 该标识仅对 API 网关有效,目标服务会直接忽略
- 在微服务环境下,API 网关会根据服务标识,路由 API 到目标服务; 在单体环境下,则无需任何处理
- 需要通过设计
api
模型生成 RPC 代码?
Web 资源网关
- 以站点做为前端资源组织结构的最顶层模型
- 一个平台(
Platform
)可包含一个或多个应用(Application
), 每个应用可包含多个前端站点(site
), 每个前端站点可包含一个或多个资源(resource
), 每个资源可对应至多一个页面(page
), 每个页面可包含一个或多个操作(action
), 每个操作涉及一个或多个接口(api
) - 每个站点、资源、操作和接口均根据用户权限(
permission
)做访问控制 - 一个前端站点面对的是一类用户或某个场景, 比如,用户登录、后台管理、门户等,均为不同的前端站点
- 所有前端站点都需要做用户鉴权,不需要登录的前端站点,
实际上是授权给了匿名用户,每个匿名用户也同样都有
Access Token
- 同一平台的多个应用之间可共享用户认证数据, 所以,已认证用户可直接在多个应用之间无缝跳转,仅需要认证一次
- 一个平台(
- 提供前端资源的获取接口,返回各用户可访问的前端站点的 JSON 结构数据
- 所有前端站点均采用 DSL 定义和生成,并根据用户权限动态增减可访问内容
- 在开发阶段,在页面、资源、操作等结构数据中需包含其 DSL 定义的位置信息, 以便于直接调试定位
- 对打包到 jar 中的前端资源文件可以采用 Nop vfs 机制做文件的分层替换, 以支持对前端资源文件的定制化修改
- 需强制设置默认站点页面,用于处理对未定义站点的 url 访问
Site DSL
本平台针对的是动态的资源授权机制,不存在拥有固定权限的角色,无法在 DSL 中配置固定数据。
<web>
<site id="common" x:abstract="true"
title="渡舟平台" runInEnv="development"
logo="/logo.svg" locale="zh">
<layout bgColor="#fff" spinner="/loading.svg"
html="/path/to/app.site-html.xml"
>
<scripts>
<!-- 入口脚本放在最开始位置 -->
<script name="renderer" url="/js/renderer-amis-0.1.0.js" />
<script name="engine" url="/js/amis/sdk-6.0.0.js" />
</scripts>
<styles>
<style name="engine" url="/css/amis/theme.css" />
<style name="renderer" url="/css/renderer-amis-0.1.0.css" />
</styles>
</layout>
</site>
<!-- 默认站点,匹配所有未匹配的站点,用于返回 404 页面 -->
<site id="default" url="*">
</site>
<!-- 登录 - Sign In;注册 - Sign Up;登出 - Sign Out -->
<site id="signin" x:prototype="common"
subTitle="用户登录"
url="/signin">
<resources>
<resource id="user-signin"
url="/path/to/signin.page.xml">
</resource>
</resources>
<layout>
<config><![CDATA[
return {
data: {},
schemaApi: site.getResource('signin').url
};
]]></config>
</layout>
</site>
<site id="main" x:prototype="common"
subTitle="门户"
url="/">
<resources>
<resource id="news"
displayName="新闻"
url="/path/to/news.page.xml">
</resource>
<resource id="blog"
displayName="博客"
url="/path/to/blog.page.xml">
</resource>
<resource id="admin"
displayName="后台管理"
url="redirect:/admin">
</resource>
</resources>
</site>
<site id="admin" x:prototype="common"
subTitle="后台管理"
url="/admin">
<resources>
<resource id="auth"
displayName="权限管理"
url="/path/to/auth.page.xml">
</resource>
<resource id="organization"
displayName="组织管理"
url="/path/to/org.page.xml">
</resource>
</resources>
</site>
</web>
site
属性列表
从前端开发的角度来看,一个
site
实际上就是一个单页面应用。
属性名 | 属性说明 | 备注 |
---|---|---|
| 前端站点唯一标识 | 需在同一个服务内保持唯一性 |
| 前端站点的访问地址,其路径相对于应用的 url | 若为 |
| 所处的运行环境 | 用于在前端显示开发状态信息、开启调试等,可选值为:
若未设置值,则视为 |
| 前端站点主标题 | |
| 前端站点副标题 | |
| 多语言环境下的当前语言 | |
| 前端站点 Logo 图片 | 资源文件相对于根站点的路径 |
| 前端站点的布局器 | 用于指定布局相关的 js 脚本和 css 样式。 布局可拆分为上下左右等多个部分以共用, 并提供错误信息的统一处理方式(弹窗或整页显示) |
| 背景色 | 前端站点的 |
| 载入动画图片 | 资源文件相对于根站点的路径 |
| 站点入口 HTML 页面的 DSL 定义文件路径 | 在其 xpl 脚本中可通过全局变量 |
| 布局器相关的 js 地址 | 指定 |
| 布局器相关的 css 地址 | 指定 |
| 布局器的配置数据生成函数 | 在函数内可访问当前站点变量 |
site.resources.resource
属性列表
资源一般为导航菜单,具体的表现形式由
site.layout
确定。
属性名 | 属性说明 | 备注 |
---|---|---|
| 资源的唯一标识 | 任意层级的资源均需在同一个前端站点内保持唯一性 |
| 资源的页面 DSL 路径 | 以 |
| 资源名称 | 一般作为导航菜单名称 |
| 图标 css 类名 |