贪多嚼不烂,每天学点蛋,今天我们来学:

多进程模型、i18n 国际化、View 模板渲染

一、多进程模型

1.1 核心目的

Node.js 单线程无法利用多核 CPU,多进程模型可解决:资源浪费、单点故障、无进程级负载均衡的问题,充分发挥服务器性能。

1.2 进程类型与分工

进程类型

数量

核心作用

稳定性

运行业务代码

Master

1个

进程管理、消息转发

非常高

Agent

1个

后台任务(长连接、定时任务)

少量

Worker

CPU核数

处理用户请求

一般

Master就是包工头、Agent是秘书、Worker是工人

1.3 启动顺序与时序

核心顺序:Master → Agent → 多个 Worker

关键时序:所有进程启动完成后,触发 egg-ready 事件(在此之前发消息可能丢失)。

1.4 进程守护与异常处理

  • Worker 异常:自动优雅退出,Master 立即重启新 Worker,保证进程总数不变。

  • Agent 异常:不自动重启,仅记录日志,需人工介入(保障稳定性)。

1.5 进程间通信(IPC)

核心 API(发送消息)

// 1. 广播到所有进程
app.messenger.broadcast(action, data);
// 2. 发送到所有 Worker
app.messenger.sendToApp(action, data);
// 3. 发送到 Agent
app.messenger.sendToAgent(action, data);
// 4. 随机发送到某个 Worker(仅 Agent 可用)
agent.messenger.sendRandom(action, data);
// 5. 发送到指定 PID 进程
app.messenger.sendTo(pid, action, data);

接收消息

// 多次监听
app.messenger.on('config-update', (data) => { console.log('收到配置:', data); });
// 仅监听一次
app.messenger.once('config-update', (data) => { console.log('首次收到配置:', data); });

1.6 Agent 适用场景

✅ 适合:长连接客户端、定时任务、全局唯一后台任务 | ❌ 不适合:处理HTTP请求、复杂业务逻辑、需频繁重启任务

1.7 实战示例:配置热更新

// agent.js(发送配置)
agent.messenger.once('egg-ready', () => {
  // 初始配置
  agent.messenger.sendToApp('config-update', { version: '1.0.0', feature: { newUI: true } });
  // 每15秒更新配置
  setInterval(() => {
    agent.messenger.sendToApp('config-update', { version: '1.0.' + Date.now() });
  }, 15000);
});

// app.js(接收配置)
app.currentConfig = null;
app.messenger.on('config-update', (config) => {
  app.currentConfig = config;
  app.logger.info(`[Worker ${process.pid}] 收到配置:`, config);
});

// controller 使用
async getConfig() {
  const { ctx } = this;
  ctx.body = { workerPid: process.pid, config: ctx.app.currentConfig };
}

二、国际化(i18n)

2.1 安装与配置

npm install @eggjs/i18n --save
// config/plugin.js
exports.i18n = { enable: true, package: '@eggjs/i18n' };

// config/config.default.js
config.i18n = {
  defaultLocale: 'zh-CN',  // 默认语言
  queryField: 'locale',    // URL参数切换:?locale=en-US
  cookieField: 'locale',   // Cookie字段名
  cookieMaxAge: '1y',      // Cookie有效期1年
};

2.2 语言切换机制

优先级(从高到低):URL Query参数 → Cookie → HTTP Header(Accept-Language)

切换后自动设置Cookie,下次访问无需重复切换。

2.3 语言文件

目录:config/locale/(必须是单数locale),支持JS/JSON两种格式

// config/locale/zh-CN.js
module.exports = {
  'Email': '邮箱',
  'Welcome back, %s!': '欢迎回来,%s!',
  'Hello {0}! My name is {1}.': '你好 {0}!我的名字叫 {1}。'
};

2.4 使用方法

// Controller 中(__ 与 gettext 等价)
ctx.__('Email'); // 邮箱
ctx.__('Welcome back, %s!', 'Shawn'); // 欢迎回来,Shawn!
ctx.__('Hello {0}! My name is {1}.', ['foo', 'bar']); // 你好 foo!我的名字叫 bar。

// 获取当前语言
const currentLocale = ctx.getLocale(); // 'zh-CN' / 'en-US'

模板中使用:{{ __('Email') }}{{ __('Welcome back, %s!', user.name) }}

2.5 注意事项

  • 目录名必须是 locale,不可写为 locals。

  • key 推荐用英文原文,方便维护(如 'Welcome back' 而非 'welcome_back')。

  • 应用、框架、插件的语言文件会合并,相同key优先级:应用 > 框架 > 插件。

三、View 模板渲染

3.1 安装与配置

npm install egg-view egg-view-nunjucks --save

// config/plugin.js
exports.nunjucks = { enable: true, package: 'egg-view-nunjucks' };

// config/config.default.js
config.view = {
  defaultViewEngine: 'nunjucks', // 默认模板引擎
  defaultExtension: '.nj',       // 默认扩展名
  mapping: { '.nj': 'nunjucks' } // 后缀与引擎映射
};

3.2 三种渲染方法

方法

作用

自动赋值ctx.body

适用场景

ctx.render(name, data)

渲染模板文件

✅ 是

最常用,直接返回渲染结果

ctx.renderView(name, data)

仅渲染模板

❌ 否

需二次处理渲染结果

ctx.renderString(tpl, data)

渲染模板字符串

❌ 否

动态模板、邮件模板

3.3 模板变量(Locals)

  • app.locals:全局变量,所有模板可访问(如应用名、版本号)。

  • ctx.locals:请求级变量,自动合并app.locals,框架自动注入ctx、request、helper。

  • 合并机制:修改app.locals不影响当前请求的ctx.locals(已缓存),赋值ctx.locals会自动合并不覆盖。

3.4 Helper 辅助函数

定义(app/extend/helper.js)

module.exports = {
  lowercaseFirst(str) { return str ? str[0].toLowerCase() + str.slice(1) : ''; },
  formatDate(date) { return new Date(date).toLocaleDateString('zh-CN'); },
  // 可访问ctx
  getCurrentUser() { return this.ctx.session.user; }
};

3.5 常用模板语法(Nunjucks)

// 变量输出
{{ name }} {{ user.email }} {{ list[0] }}

// 条件判断
{% if user.isVip %}VIP{% elif user.isMember %}会员{% else %}普通{% endif %}

// 循环
{% for item in list %}{{ loop.index }}: {{ item.name }}{% endfor %}

// 过滤器
{{ name | upper }} {{ price | default('免费') }}

3.6 注意事项

  • Egg中ctx.state ≡ ctx.locals,推荐使用ctx.locals。

  • 模板默认根目录:app/view/,渲染路径可省略默认扩展名.nj。

  • renderString无默认引擎时,需手动指定viewEngine: 'nunjucks'。

四、测试接口汇总

接口

功能

说明

http://localhost:7001/

首页

显示当前环境

http://localhost:7001/ipc-config

IPC通信示例

查看Agent发送的配置(每15秒更新)

http://localhost:7001/i18n

i18n示例

默认显示中文

http://localhost:7001/i18n?locale=en-US

切换语言

URL参数切换为英文

http://localhost:7001/view

View渲染示例

综合展示模板功能

http://localhost:7001/view/render-view

renderView方法

演示手动赋值ctx.body

http://localhost:7001/view/render-string

renderString方法

演示渲染字符串模板

五、核心要点总结

5.1 多进程模型

  • 三类进程分工明确,Master管理、Agent处理公共任务、Worker处理请求。

  • IPC通信依赖messenger,必须在egg-ready事件后发送消息。

  • Worker异常自动重启,Agent异常需人工处理。

5.2 i18n 国际化

  • 核心API:ctx.__() 或 ctx.gettext(),支持两种占位符(%s/%d/%j 和 {0}/{1})。

  • 语言切换优先级:URL参数 > Cookie > HTTP Header。

  • 语言文件存于config/locale/,key推荐用英文原文。

5.3 View 模板渲染

  • 优先使用ctx.render(),其余两种方法需手动赋值ctx.body。

  • app.locals全局变量,ctx.locals请求级变量,自动合并并注入常用对象。

  • Helper通过app/extend/helper.js扩展,可访问ctx,用于模板格式化。

六、最佳实践

  • Agent:仅放长连接、定时任务等全局唯一任务,保证代码稳定。

  • i18n:key用英文,保持各语言文件key一致,合理设置默认语言。

  • View:复杂逻辑放Controller/Service,Helper职责单一,合理使用locals变量。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐