基于nodejs实现服务端内核引擎

Elpis-Core 深度理解:企业级 Node.js 框架架构解析

什么是 Elpis-Core?

Elpis-Core 是一个基于 Koa 的 Node.js 内核实现。

分层架构

三层设计

markdown 复制代码
┌─────────────────────────────────────┐
│  Controller 层(业务逻辑入口)        │
│  - 接收请求                          │
│  - 参数校验                          │
│  - 调用 Service                      │
│  - 返回响应                          │
└─────────────────────────────────────┘
           ↓
┌─────────────────────────────────────┐
│  Service 层(数据处理)               │
│  - 业务逻辑处理                      │
│  - 数据库操作                        │
│  - API 调用                          │
│  - 数据转换                          │
└─────────────────────────────────────┘
           ↓
┌─────────────────────────────────────┐
│  Middleware 层(横切关注点)          │
│  - 参数校验                          │
│  - 权限验证                          │
│  - 异常处理                          │
│  - 日志记录                          │
└─────────────────────────────────────┘

模块化加载

Loader 系统

  • 先扫描目录
  • 再加载模块
  • 然后挂载到 app
  • 支持层级嵌套

启动入口(index.js)

核心流程

javascript 复制代码
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 项目名称
     *  homePath 项目首页
     * }
     */
  start(options) {
    // 实例化
    const app = new Koa();

    // 应用配置
    app.options = options; 
    
    // 项目基础路径
    app.baseDir = process.cwd();

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

    // 初始化环境变量
    app.env = env();
    console.log(`-- [start] env: ${app.env.get()} --`);

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

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

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

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

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

    // 加载控制器 controller
    controllerLoader(app);
    console.log(`-- [start] load controller done --`);
    
    // 注册全局中间件
    // app/middlewareLoader.js
    try{
      require(`${app.businessPath}${sep}middleware.js`)(app);
      console.log(`-- [start] load global middleware done --`);
    }catch(e){
      console.log(`[exception] there is no global 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);
    }
  },
};

关键点

  • app 对象是整个框架的核心
  • 所有模块都挂载到 app
  • Loader 按顺序加载,有依赖关系
  • 路由最后加载,确保中间件已注册

Loader 加载机制

Loader 系统概览

Elpis-Core 提供了 7 个 Loader,每个负责加载特定类型的模块:

Loader 功能 输出 依赖
configLoader 加载配置 app.config env
extendLoader 加载扩展 扩展 app
middlewareLoader 加载中间件 app.middlewares
routerSchemaLoader 加载校验规则 app.routerSchema
serviceLoader 加载服务 app.service config
controllerLoader 加载控制器 app.controller service
routerLoader 加载路由 注册路由 controller, routerSchema

Loader 工作原理

通用加载流程

javascript 复制代码
// 1. 扫描目录
const fileList = glob.sync(path.resolve(directory, '**/**.js'));

// 2. 遍历文件
fileList.forEach(file => {
  // 3. 提取文件名
  let name = extractFileName(file);
  
  // 4. 转换命名(驼峰)
  name = name.replace(/[_-][a-z]/ig, s => s.substring(1).toUpperCase());
  
  // 5. 加载模块
  const module = require(file)(app);
  
  // 6. 挂载到 app
  app[category][name] = module;
});

1. Middleware Loader

中间件,采用洋葱圈模型,实现请求参数校验、异常捕获等功能,可以横向拓展。

2. Controller Loader

请求控制,进行http统一处理,api响应等业务处理能力。

3. Service Loader

服务层,负责主要业务逻辑,对数据进行处理,实现数据的获取返回等等。

4. Config Loader

配置层,先行加载,不同配置文件加载不同环境配置信息等。

5. Router Schema Loader

对router进行校验,通过加载json-schema对api进行规则约束。

6. Extend Loader

加载extend模块,将其挂载到app示例,实现横向功能扩展。

7. Router Loader

加载路由模块,根据router-schema动态生成路由并挂载到koa实例上,统一管理。

中间件执行流程

scss 复制代码
        ┌─────────────────────────────┐
        │     请求进入                 │
        └─────────────────────────────┘
                    ↓
        ┌─────────────────────────────┐
        │  koa-static (静态文件)       │  ← 第一层
        └─────────────────────────────┘
                    ↓
        ┌─────────────────────────────┐
        │  koa-nunjucks (模板引擎)     │  ← 第二层
        └─────────────────────────────┘
                    ↓
        ┌─────────────────────────────┐
        │  bodyParser (请求解析)       │  ← 第三层
        └─────────────────────────────┘
                    ↓
        ┌─────────────────────────────┐
        │  errorHandler (异常处理)     │  ← 第四层
        └─────────────────────────────┘
                    ↓
        ┌─────────────────────────────┐
        │  apiSignVerify (签名校验)    │  ← 第五层
        └─────────────────────────────┘
                    ↓
        ┌─────────────────────────────┐
        │  apiParamsVerify (参数校验)  │  ← 第六层
        │  - 校验 headers              │
        │  - 校验 query                │
        │  - 校验 body                 │
        └─────────────────────────────┘
                    ↓
        ┌─────────────────────────────┐
        │  koa-router (路由匹配)       │  ← 第七层
        │  - ctx.params 注入           │
        └─────────────────────────────┘
                    ↓
        ┌─────────────────────────────┐
        │  paramsValidator (参数校验)  │  ← 第八层
        │  - 校验 params               │
        └─────────────────────────────┘
                    ↓
        ┌─────────────────────────────┐
        │  Controller (业务逻辑)       │  ← 第九层
        └─────────────────────────────┘
                    ↓
        ┌─────────────────────────────┐
        │     响应返回                 │
        └─────────────────────────────┘

中间件注册顺序

javascript 复制代码
// app/middleware.js
module.exports = (app) => {
  // 1. 静态文件服务
  app.use(koaStatic('./app/public'));
  
  // 2. 模板渲染引擎
  app.use(koaNunjucks({ ext: 'tpl', path: './app/public' }));
  
  // 3. 请求体解析
  app.use(bodyParser());
  
  // 4. 异常捕获
  app.use(app.middlewares.errorHandler);
  
  // 5. 签名校验
  app.use(app.middlewares.apiSignVerify);
  
  // 6. 参数校验(headers/query/body)
  app.use(app.middlewares.apiParamsVerify);
};

params 校验的特殊处理

问题:params 在路由匹配后才注入,无法在路由前校验。

解决方案

javascript 复制代码
// elpis-core/loader/router.js
const { createParamsValidator } = require('../middleware/validate');

module.exports = (app) => {
  const router = new KoaRouter();
  
  // 在路由内部注册 params 校验中间件
  router.use(createParamsValidator(app));
  
  // 注册路由...
};

执行时机

csharp 复制代码
请求 → apiParamsVerify → koa-router → paramsValidator → Controller
        ↑ 校验headers等    ↑ 注入params   ↑ 校验params

总结

搭建内核引擎不是要去理解业务需求,而是对程序的架构思维理解,如何通过统一约束,通过同种方式加载不同功能,理解生命周期去优化执行顺序,是应用页面开发到架构设计的过渡。

相关推荐
触底反弹3 小时前
🧠 搞懂 Token,才算真正入门大模型——从分词原理到 Embedding 语义实战
javascript·人工智能·算法
free353 小时前
AST Interpreter 的设计:为什么分 evaluate() 和 execute()
javascript
等咸鱼的狸猫4 小时前
JavaScript 隐式类型转换:从入门到精通
javascript
kyriewen7 小时前
我用 Codex 重写了同事维护三年的代码,他没说谢谢——而是找了领导
前端·javascript·ai编程
铁皮饭盒7 小时前
S3已成为文件存储标准,阿里/腾讯/华为云都支持,Bun率先原生支持
前端·javascript·后端
Cobyte7 小时前
22.Vue Vapor 组件 props 的实现
前端·javascript·vue.js
浮生望9 小时前
JS字符串与回文算法:从包装类到双指针的面试进阶之路
javascript·算法
疯狂的魔鬼9 小时前
一套 Schema 驱动四视图:记 useCrudSchemas 的设计与实践
前端·javascript·typescript
weedsfly9 小时前
栈和堆:JavaScript 内存的“旅馆”和“仓库”
前端·javascript·面试