elpis 全栈里程碑一总结

0 阅读4分钟

elpis 里程碑一总结

1.项目架构设计

image.png

1-1.聚焦buff层

buff分三个层级:

  1. 接入层: router接口路由分发, router-schema路由规则校验 ,middleware路由中间件
  2. 业务层: controller处理器, env环境分发,config提取,extend服务拓展,schedule定时任务
  3. 服务层: service处理器

1-2.而elpis-core就是基于buff层设计的用node.js+koa

2.对于elpis-core的理解

graph TD
运行前磁盘文件 --> 解析器  -->  运行时内存

1.elpis-core是一个自动把文件挂载到koa实例上的一个引擎,也是一个轻量版的egg.js内核,他的设计理念是约定式加载,通过写好的各种loader,从预先约定好的目录结构中读取各种js 文件,按照一定的顺序挂载到由koa 创建的app 实例上面,可通过app.midddleware.${目录}.${文件}访问

  • 例如:
 *   app/service
 *     |
 *     |-- custom-module
 *          |
 *          |-- custom-service.js
 *  => app.service.customModule.customservice

3.elpis-core的结构

loader说明
server.js业务模块的自动加载
extend.js自动加载扩展,例:外部日志工具log4js
router.js引入了一个Koa挂载 extend 到 app 上,这个extend可以用来引入日志工具,先把所有 app/router的文件加载到KoaRouter 下,再将路由注册到 app下
routerSchema.js对应router的参数的一个具体校验解释文件,
controller.js控制器自动加载
config.js配置区分 本地/测试/生产环境,通过env环境读取不同文件配置 env.config,然后通过 env.config 覆盖 default.config 加载到 app.config 中
middleware.js引入自定义中间件loader,如模板渲染中间件等,让中间件自动加载

4.koa内部模型(洋葱圈模型)

image.png

什么是洋葱圈模型?中间件执行流程的形象比喻,通过 next() 让代码先一层层进入,再一层层退出,像切开的洋葱一样。
为什么是先进后出?因为 next() 会暂停当前函数,调用下一个函数,这符合调用栈的后进先出(LIFO) 特性。
有什么好处?每个中间件可以在请求前响应后都执行逻辑,实现对称处理,非常适合日志、认证、错误处理等场景。

5.相关中间件

中间件说明
koa-static解决静态资源的加载,可以在app/public目录下自动加载相关的静态资源,如:css、png等。
koa-nunjucks-2用于服务器端渲染 HTML(SSR), 全局中间件中引入了koa-nunjucks-2,挂载到了ctx上,从而使得ctx上有render方法
koa-bodyparser用于解析 HTTP 请求体,并将数据挂载到 ctx.request.body ,因为Koa 默认无法直接获取请求体中的 body 数据。
log4js为日志工具属于Extend,通过 app.logger.info 记录日志并落地磁盘。
api-params-verify参数校验基于 JSON-Schema 和 Ajv,配合中间件使用,确保接口数据安全。
api-sign-verify接口签名防止数据篡改。前后端约定 Key,通过 MD5(参数+Key) 校验合法性。
error-handler对一些异常的报错进行处理,避免用户请求服务出问题,返回一些不必要的内容

6.SSR

BFF部署在服务器内网,向后端多个服务发起请求延迟极低,甚至可以并行请求。这远比在浏览器端一个一个请求后端API要快得多,所以BFF层提供了一个完美的地方来做SSR所需要的数据准备工作

1.当前项目提供SSR,在router中调用controller中方法,在controller中写了renderPage方法,因为引入了koaNunjucks,在ctx中可以拿到render方法,所以可以直接在浏览器中输入路由地址渲染出所对应的页面

//middleware
module.exports = (app)=>{

    // 配置静态根目录
    const koaStatic = require('koa-static');
    app.use(koaStatic(path.resolve(process.cwd(), `./app/public`)));
    
        // 模板渲染引擎
        const koaNunjucks = require('koa-nunjucks-2');
        app.use(koaNunjucks({
            ext: 'tpl',
            path: path.resolve(process.cwd(), `./app/public`),
            nunjucksConfig: {
                noCache:true,
                trimBlocks: true
            }
        }));
}
//controller
module.exports = (app) => { 
    return class ViewController {
        /**
         * 渲染页面
         * @param {*} ctx 上下文
         */
        async renderPage(ctx){
            await ctx.render(`dist/entry.${ctx.params.page}`,{
                name:app.option?.name,
                env:app.env.get(),
                option:JSON.stringify(app.option),
            });
        }
    }
}
//router
module.exports = (app,router) => { 
    const {view: ViewController } = app.controller;
    // 用户输入http://ip:
    router.get('/view/:page',ViewController.renderPage.bind(ViewController))
}

7.为何 Controller 和 Service 要用class?

在 Elpis-Core 中,Controller 和 Service 被设计为 Class(类) ,这带来了极高的可扩展性。

  • 复用性:可以定义一个 BaseController(基类),封装通用方法(如 success 成功返回、fail 错误返回)。
  • 继承性:业务 Controller(如 ProjectController)继承基类,直接复用公共方法。 总结: BFF层级(后端)其实主要由解析引擎以及业务模块两大板块组成

8.总结

解析引擎elpis-core的主要作用是将各个业务模块聚合在一起并保证其在程序内存中正常运行。这也是例如Eggjs、Nextjs、Nestjs等框架做的事情,也是这些框架设计背后的思想