基于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

总结

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

相关推荐
PYB38 小时前
【Web·JS·基础】函数的使用和展运算符...objs
前端·javascript
默_笙9 小时前
🚥 给 RAG 装一台心电监护仪:LangSmith 全链路观测(上)
前端·javascript
变与不变80611 小时前
js同步和异步难点重点详解
开发语言·javascript·ecmascript
Dovis(誓平步青云)11 小时前
多个链接不等于多份证据,新闻核验看板怎样合并来源
java·服务器·前端·javascript·人工智能·pdf·电脑
Dovis(誓平步青云)12 小时前
几个方案来回选不定?做一个随时切换的候选推荐页
android·java·服务器·开发语言·javascript·数据库·智能化
可乐鸡翅yeah_13 小时前
fmp4 碎片 MP4 格式 HLS 流,和传统 TS 分片有什么不一样
开发语言·javascript·ios·音视频·safari·m3u8·m3u8在线播放
ss27314 小时前
AI全栈实战 | 2.3-01 组件库实战:Element Plus 怎么搭出专业界面,过度封装为什么成维护负担
前端·javascript·elementui·vue
福兮说15 小时前
URL 编码的七个坑:c++ 传到后端变空格、%25 套娃、截断 emoji 直接报错
开发语言·前端·javascript·node.js·url
小的时候可菜了15 小时前
JS 异步的本质:从单线程到 thenable(一条进化链)
开发语言·前端·javascript
可乐鸡翅yeah_15 小时前
hls.js 配置 loadStartPosition,点播起始播放位置踩坑
开发语言·javascript·网络协议·ecmascript·m3u8在线