core - 核心
核心模块用于模块的加载与服务启动
依赖模块
无
配置项
| 配置项 | 类型 | 默认值 | 功能 |
|---|---|---|---|
| env | string | development | 执行环境,开发环境为 development 生产环境为 production,一般通过 NODE_ENV 环境变量指定 |
| keys | string[] | 无 | Cookie 签名密钥 |
| proxy | boolean | false | 信任代理头信息,例如前级为 Nginx 为了取得真实客户端 ip 地址需要设置为 true |
| subdomainOffset | number | 无 | 子域名位置 |
| proxyIpHeader | string | X-Forwarded-For | 代理后客户端真实 ip 头字段名 |
| maxIpsCount | number | 0 | 多级代理后允许的 ip 数量,0 无限制 |
Core 挂载项
| 挂载项 | 类型 | 功能 |
|---|---|---|
| name | string | 应用名称,获取顺序: env.APP_NAME、hostname |
| startTime | number | 启动时间: 毫秒时间戳 |
| app | Koa | 取得 Koa 实例 |
| loadedModules | LoadedModule[] | 已载入的模块 |
| server | Server | 取得 http.Server 实例 |
| debug | Debugger | core debug 方法 |
Context 挂载项
| 挂载项 | 类型 | 功能 |
|---|---|---|
| core | Core | Core 模块实例 |
全局方法 [v4.0+]
通过全局方法可以在任何地方获取 Core 实例和当前请求上下文,不再需要层层传递参数。
| 名称 | 功能 |
|---|---|
$initCore(opt?) | 初始化全局 Core 实例,默认启用 asyncLocalStorage。如果实例已存在则抛出异常 |
$getCore() | 取得全局 Core 实例。如果实例不存在则抛出异常 |
$core | $getCore() 的快捷方式,通过 Proxy 代理访问 Core 实例的属性和方法 |
$getContext(force?) | 取得当前请求上下文。force 默认为 true,无法取得时抛出异常;设为 false 则返回 undefined |
$ctx | $getContext() 的快捷方式,通过 Proxy 代理访问 Context 的属性和方法 |
$debug / createDebug | 带有请求信息和调用位置信息的 debug 输出工具,支持 extend() 扩展命名空间 |
import { $initCore, $getCore, $core, $getContext, $ctx, $debug } from '@zenweb/core';
// 初始化全局 Core 实例(通常在入口文件中调用一次)
const core = $initCore();
// 在任意位置取得 Core 实例
$core.name; // 等同于 $getCore().name
// 在请求处理链中取得当前请求上下文
$ctx.path; // 等同于 $getContext().path
// 带有请求信息和调用位置信息的 debug 输出
$debug('查询参数: %o', $ctx.query);
// 扩展 debug 命名空间
const myDebug = $debug.extend('mymod');
myDebug('自定义模块日志');
自定义模块入口样例代码
import { SetupFunction } from '@zenweb/core';
// 自定义模块配置项
export interface MyModOption {}
// 是否有 opt 参数或者其他参数由模块开发者自定义
export default function (opt?: MyModOption): SetupFunction {
// 返回函数的名称将作为模块名称显示
return function mymodname(setup) {}
}
SetupHelper 完整 API
SetupHelper 是模块安装时的核心助手对象,在模块安装函数中作为参数传入,提供了丰富的 API 用于扩展框架能力。
defineCoreProperty(prop, descriptor)
在 Core 实例上定义属性。如果属性已存在则抛出异常,防止模块间冲突。
import { SetupFunction } from '@zenweb/core';
export default function mymod(setup: SetupFunction) {
return function mymod(setup) {
// 定义 Core 上的属性
setup.defineCoreProperty('myService', {
value: new MyService(),
});
// 也可以使用 getter 实现延迟初始化
setup.defineCoreProperty('config', {
get() {
return loadConfig();
},
});
};
}
defineContextProperty(prop, descriptor)
在请求上下文 (Context) 上定义属性。每个请求都可以访问该属性。如果属性已存在则抛出异常。
import { SetupFunction } from '@zenweb/core';
export default function (): SetupFunction {
return function mymod(setup) {
// 在 Context 上定义方法
setup.defineContextProperty('getUserId', {
value: function () {
return this.headers['x-user-id'];
},
});
// 定义 getter 属性
setup.defineContextProperty('clientIp', {
get() {
return this.ip || this.ips?.[0];
},
});
};
}
defineContextCacheProperty(prop, getter)
在 Context 上定义懒缓存属性。属性第一次被访问时执行 getter 函数,之后直接返回缓存值。每个请求独立缓存,适合在请求生命周期内多次访问的耗时操作。
import { SetupFunction } from '@zenweb/core';
export default function (): SetupFunction {
return function mymod(setup) {
// 第一次访问时创建数据库连接,后续复用缓存
setup.defineContextCacheProperty('dbConn', (ctx) => {
setup.debug('创建数据库连接');
return createConnection(ctx.core.dbConfig);
});
// 第一次访问时解析用户信息
setup.defineContextCacheProperty('currentUser', async (ctx) => {
const token = ctx.headers['authorization'];
if (!token) return null;
return verifyToken(token);
});
};
}
middleware(fn)
注册全局中间件,等同于 app.use(middleware)。中间件按照模块加载顺序执行。
import { SetupFunction, Context, Next } from '@zenweb/core';
export default function (): SetupFunction {
return function mymod(setup) {
setup.middleware(async function myMiddleware(ctx: Context, next: Next) {
console.log('请求开始:', ctx.path);
await next();
console.log('请求结束:', ctx.status);
});
};
}
after(fn)
注册回调函数,在所有模块初始化完成后执行。适合需要依赖其他模块已完成初始化的场景。
import { SetupFunction } from '@zenweb/core';
export default function (): SetupFunction {
return function mymod(setup) {
setup.after(async () => {
// 所有模块都已加载完毕,可以安全使用其他模块提供的功能
setup.debug('所有模块初始化完成');
});
};
}
destroy(fn)
注册销毁回调,在服务停止时调用。框架会等待销毁方法完成后再关闭连接。适合释放资源(如数据库连接、文件句柄等)。
import { SetupFunction } from '@zenweb/core';
export default function (): SetupFunction {
return function mymod(setup) {
let connection: DatabaseConnection;
setup.after(async () => {
connection = await createConnection();
});
// 服务停止时关闭连接
setup.destroy(async () => {
if (connection) {
await connection.close();
setup.debug('数据库连接已关闭');
}
});
};
}
assertModuleExists(name, msg?)
断言指定模块已安装,如果不存在则抛出异常。用于在模块安装阶段声明依赖关系。
import { SetupFunction } from '@zenweb/core';
export default function (): SetupFunction {
return function mymod(setup) {
// 检查必需的依赖模块
setup.assertModuleExists('inject', 'mymod 模块需要先安装 @zenweb/inject');
setup.assertModuleExists('controller');
// 模块初始化逻辑...
};
}
Core 生命周期
Core 模块定义了完整的应用生命周期,按照 boot → start → stop 的顺序执行。
boot - 模块初始化
boot() 方法按模块加载顺序依次执行所有模块的安装函数,之后执行所有通过 after() 注册的回调。
import { Core } from '@zenweb/core';
const core = new Core();
core.setup(moduleA);
core.setup(moduleB);
// 执行所有模块的 setup 函数,然后执行所有 after 回调
await core.boot();
start - 启动服务
start() 方法依次执行 boot() → listen() → 注册信号处理。
import { Core } from '@zenweb/core';
const core = new Core();
core.setup(moduleA);
core.setup(moduleB);
// 启动应用:初始化模块 → 监听端口 → 注册信号处理
// 默认端口 7001,也可通过环境变量 PORT 指定
await core.start(3000);
stop - 停止服务
stop() 方法按照模块加载的逆序依次调用各模块的 destroy() 回调,确保资源正确释放。
import { Core } from '@zenweb/core';
const core = new Core();
// ...
await core.start();
// 手动停止服务(通常由信号触发,不需要手动调用)
await core.stop();
信号处理
start() 启动后会自动注册 SIGTERM 和 SIGINT 信号处理,收到信号后触发优雅关闭流程。
// 应用启动后,以下方式可以触发停止:
// - 发送 SIGTERM 信号:kill <pid>
// - 发送 SIGINT 信号:Ctrl+C(终端模式)
// - Docker/K8s 发送停止信号
优雅关闭
Core 内置了优雅关闭(Graceful Shutdown)机制,确保服务停止时不会丢失正在处理的请求:
- 停止接收新请求:关闭 HTTP 服务器监听,不再接受新的连接
- 按逆序销毁模块:按照模块加载的相反顺序,依次调用各模块的
destroy()回调,等待每个模块清理完成 - 防重复处理:通过
_stopping标记防止重复触发关闭流程 - 强制退出保护:如果在关闭过程中再次收到停止信号,会打印当前活跃资源信息并强制退出
import { $initCore } from '@zenweb/core';
const core = $initCore();
core.setup(function mymod(setup) {
setup.destroy(async () => {
// 在这里释放模块持有的资源
// 例如关闭数据库连接、停止定时任务等
// Core 会等待此方法完成后继续关闭流程
});
});
await core.start();
// 收到 SIGTERM/SIGINT 信号后自动触发优雅关闭