里程碑一:elpis-core基于KOA实现轻量化服务引擎框架

0 阅读4分钟

引言

学习课程来自于抖音“哲玄前端”课程(《大前端全栈实践课》),从零开始做一个企业级的全栈应用框架。

一、elpis-core整体架构设计

elpis-core是基于koa实现的类似于egg的轻量化服务端。通过koa实例,将各种loader文件进行解析并加载到内存中。

1. BFF

BFF架构设计.jpeg

BFF架构设计

BFF(Backend For Frontend)中间层,一种架构设计,主要用于解决前后端数据协作及微服务框架的数据聚合问题。

(1). 接入层

  • router-schema

基于json-schemaajv校验器,对请求头(headers),请求体(params/body/query)进行合法校验。

  • router

基于koa-router实现动态路由分发,支持 API 与页面路由,具备分组管理与中间件绑定能力。

  • middleware

请求处理管线,采用洋葱圈模型,支持全局或特定 API 配置,可实现签名验证、参数校验、异常处理等功能。

(2). 业务层

  • env

管理环境变量,自动识别NODE_ENV,默认本地(local)。

  • config

多环境配置,通过配置config.{env}.js,提取各环境变量。

  • extend

全局功能(插件/工具)拓展,直接挂载至app实例上。(类似于日志等)

  • controller

封装基类,处理具体逻辑,整合参数

(3). 服务层

  • service

封装数据库读写与外部服务调用,为controller提供原子化数据操作接口。

2. 洋葱圈模型

洋葱圈模型.png

洋葱圈模型

基于Koa的洋葱模型,每个请求都会经过一系列中间件处理,形成一个完整的处理管道。这种设计使得横切关注点(如日志、错误处理、参数校验)能够优雅地实现。

二、设计原则(思想)

elpis-core遵循的原则(思想)是约定大于配置,有清晰的目录结构,按照一套统一的约定开发模式。同时采用模块化的设计,每个模块责任单一,互相独立,方便维护和扩展。

elpis
  |-- app // 文件目录
  |   |-- controller // 业务逻辑处理
  |   |-- extend // 全局拓展
  |   |-- middleware // 中间件
  |   |-- public // 静态资源
  |   |-- router // 路由
  |   |-- router-schema // 路由校验规则
  |   |-- service // api及数据处理
  |   |-- middlewares.js // 全局中间件
  |-- config // 环境配置文件
  |   |-- -config.beta.js   //测试环境
  |   |-- -config.default.js  //默认环境
  |   |-- -config.local.js  //本地环境
  |   |-- -config.prod.js  //生产环境
  |-- elpis-core // 引擎内核
  |   |-- loader
  |   |   |-- config
  |   |   |-- controller
  |   |   |-- extend
  |   |   |-- middleware
  |   |   |-- router-schema
  |   |   |-- router
  |   |   |-- service
  |   |-- env.js  //环境获取
  |   |-- index.js
  |-- index.js // 入口文件

三、 elpis-core的设计实现

1.加载器功能

通过index.js读取、解析、加载各个目录下的loader文件,并挂载到koa实例的对应属性上,实现将文件转化为内存(运行时)

const Koa = require("koa");
const path = require("path");
const { sep } = path; //兼容不同操作系统上的斜杠
const env = require("./env");

const middlewareLoader = require("./loader/middleware");
const routerSchemaLoader = require("./loader/router-schema");
const routerLoader = require("./loader/router");
const controllerLoader = require("./loader/controller");
const serviceLoader = require("./loader/service");
const configLoader = require("./loader/config");
const extendLoader = require("./loader/extend");

module.exports = {
  /**
   * 启动项目
   * @params options 项目配置
   * options = {
   *  name // 项目名称
   *  homePage // 项目首页
   * }
   */

  start(options = {}) {
    //koa实例
    const app = new Koa();

    //应用配置
    app.options = options;

    //基础路径
    app.baseDir = process.cwd();

    //业务路径
    app.businessPath = path.resolve(app.baseDir, `.${sep}app`);

    //初始化环境配置
    app.env = env();

    //加载middleware
    middlewareLoader(app);
    console.log(`--[start] load midlleware done --`);

    //加载routerSchema
    routerSchemaLoader(app);
    console.log(`--[start] load routerSchema done --`);

    //加载controller
    controllerLoader(app);
    console.log(`--[start] load controller done --`);

    //加载service
    serviceLoader(app);
    console.log(`--[start] load servic done --`);

    //加载config
    configLoader(app);
    console.log(`--[start] load config done --`);

    //加载extend
    extendLoader(app);
    console.log(`--[start] load extend done --`);

    //注册全局中间件
    try {
      require(`${app.businessPath}${sep}middleware.js`)(app);
      console.log(`--[start] load golbal middleware done --`);
    } catch (e) {
      console.log("[exception] there is no golbal middleware file.");
    }

    //加载router
    routerLoader(app);
    console.log(`--[start] load router done --`);

    //启动服务
    try {
      const port = process.env.PORT || 8080;
      const host = process.env.Ip || "0.0.0.0";
      app.listen(port, host);
      console.log(`Server running on port: ${port}`);
    } catch (e) {
      console.log(e);
    }
  },
};

2.加载器顺序

通过 Loader 的加载顺序管理模块生命周期

  1. 环境配置加载

  2. 加载基础服务

    • 中间件
    • 路由检验规则
    • 服务
    • 控制器
    • 拓展功能
  3. 注册全局中间件

  4. 注册路由

  5. 启动应用

3.页面渲染

通过koa-nunjucks-2,提供的一个render函数,对页面进行渲染

扩展

1、koa:

Koa | Koa(koajs)中文文档 | Koa(koajs)中文网

Koa 使用Promise和异步功能来摆脱回调地狱的应用程序,并简化错误处理。 它暴露了自己的ctx.request和ctx.response对象,而不是 node 的req和res对象。

2、koa-bodyparser

koa-bodyparser是一个用于 Koa 框架的中间件,用于解析 HTTP 请求的主体(body)。它支持解析 JSON、表单(form)和文本(text)类型的主体,但不支持解析 multipart 格式的数据。

3、ghooks

GitCode - 全球开发者的开源社区,开源代码托管平台

package.json内配置

  "scripts": {
    "lint": "eslint --quiet --ext js,vue .",
    "test": "_ENV='local' mocha  test/**/*.js"
  },
 "config": {
   "ghooks": {
      "commit-msg": "validate-commit-msg",
      "pre-commit": "npm run lint"
    }
  }

4、log4js(日志工具)

log4js

log4js是一个流行的Node.js日志记录库

5、json-schema/Ajv

JSON Schema 是用于验证 JSON 数据结构的强大工具,Schema可以理解为模式或者规则
Ajv 是一个用于 JavaScript 应用的安全性和可靠性的 JSON 结构校验器
通过 json-schema 和 ajv 对API规则进行约束,配合api-params-verify中间件使用

 schemas.headers.$schema = $schema
 validate = ajv.compile(schemas.headers)
 vaild = validate(headers)

6、koa-nunjucks-2

koa-nunjucks-2

用来作为模板引擎,为 koa 应用提供页面渲染功能
默认会在请求上下文(context)上增加render()方法,通过调用ctx.render('模板名', 数据)就可以渲染页面

 const koaNunjucks = require('koa-nunjucks-2');
 app.use(koaNunjucks({
 ext: 'tpl',
 path: path.resolve(process.cwd(), './app/public'),
 nunjucksConfig: {
       trimBlocks: true,
       noCache: true
    }
  })
 );