news 2026/9/20 22:36:27

Egg 框架内置对象完全指南:Application、Context、Request、Response、Controller、Service、Helper、Config 与 Logger

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Egg 框架内置对象完全指南:Application、Context、Request、Response、Controller、Service、Helper、Config 与 Logger
  • 后端
  • Web框架

【免费下载链接】egg

🥚 Born to build better enterprise frameworks and apps with Node.js & Koa

项目地址:https://gitcode.com/gh_mirrors/egg11/egg
点击查看免费下载

导读

本文基于 Egg 框架的 Framework Built-in Objects 官方文档,系统梳理框架中面向开发者高频使用的九类内置对象:从 Koa 继承的 Application、Context、Request、Response,以及框架扩展出的 Controller、Service、Helper、Config、Logger。这些对象贯穿 Egg 应用的每一个文件,是阅读后续控制器、服务、中间件、调度任务等文档的前提。读完本文,你将掌握每个内置对象的生命周期定位(应用级/请求级)、全部获取途径与适用场景,并能结合源码理解它们底层是如何被装载、实例化与关联的。

一、内置对象全景:谁继承自 Koa,谁由 Egg 扩展

框架在 Koa 之上构建,内置对象分为两类:

  • 继承自 Koa 的对象:Application、Context、Request、Response。它们的语义与 Koa 保持一致,Egg 在此基础上做了能力增强(例如 Application 增加了 Loader 装载机制、Context 挂载了 Service 与 Helper)。
  • Egg 扩展出的对象:Controller、Service、Helper、Config、Logger、Subscription。这些对象承载了 Egg 的约定式目录结构与工程化能力,在后续文档(控制器、服务、中间件、调度等)中会反复出现。

从源码看,lib/egg.js 中this.Controller = BaseContextClass;this.Service = BaseContextClass;,说明 Controller 与 Service 的基类实际是同一个BaseContextClass;而 lib/core/base_context_class.js 进一步为它注入了基于当前 Context 的loggergetter。这意味着三类对象天然共享同一套“上下文感知”设计。

二、Application:全局单例应用对象

Application 是应用级(全局)单例对象,一个应用只实例化一次。它继承自 Koa 的 Application,是挂载全局方法、对象与配置的容器。你可以通过 框架扩展 在插件或应用层面对其进行扩展。

2.1 获取方式一:Loader 回调参数

几乎所有由 Loader 装载的文件(Controller、Service、Schedule 等)都会导出一个以app为参数的函数,Loader 调用该函数时注入 app:

  • 应用启动脚本(app-start.md):
// app.js module.exports = app => { app.cache = new Cache(); };
  • 控制器文件(controller.md):
// app/controller/user.js module.exports = app => { return class UserController extends app.Controller { * fetch() { this.ctx.body = app.cache.get(this.ctx.query.id); } }; };

说明:* fetch()为 generator 函数写法,Egg 同时支持async fetch(),两种写法均被框架支持。

2.2 获取方式二:通过 Context 与实例属性

  • 与 Koa 一致,在 Context 上可通过ctx.app访问 Application:
// app/controller/user.js module.exports = app => { return class UserController extends app.Controller { * fetch() { this.ctx.body = this.ctx.app.cache.get(this.ctx.query.id); } }; };
  • 在继承自 Controller / Service 基类的实例对象中,通过this.app访问:
// app/controller/user.js module.exports = app => { return class UserController extends app.Controller { * fetch() { this.ctx.body = this.app.cache.get(this.ctx.query.id); } }; };

2.3 源码佐证:Application 的装载与常用成员

从 lib/application.js 可以看到,Application 构造函数中调用this.loader.load()完成目录装载,并执行配置 dump;同时通过 lib/egg.js 挂载了messengerhttpclientloggersControllerServiceBaseContextClass等核心成员。此外app.config.keys(config/config.default.js)用于 Cookie 签名与加密,若缺失会在keysgetter 中抛出错误提示(lib/application.js)。

三、Context:请求级上下文

Context 是请求级对象,继承自 Koa.Context。每收到一个请求,框架就实例化一个 Context,封装用户的请求信息,并提供读取请求参数、设置响应信息的便捷方法。框架会把所有 Service 挂载到 Context 实例上,一些插件也会在 Context 上挂载额外方法与对象(例如 egg-sequelize 会把所有 Model 挂载到 Context)。

3.1 获取方式:Middleware、Controller、Service

Context 最常见的获取场景是中间件、控制器与服务中:

  • 控制器内的获取方式见上文示例(this.ctx);服务中的获取方式与控制器一致(this.ctx)。
  • Egg 中间件同时兼容 Koa v1 与 Koa v2 两种写法,访问 Context 的方式略有差异:
// Koa v1 function* middleware(next) { // this 是 Context 实例 console.log(this.query); yield next; } // Koa v2 async function middleware(ctx, next) { // ctx 是 Context 实例 console.log(ctx.query); }

中间件细节可参考 middleware.md。

3.2 非请求场景:createAnonymousContext()

在某些非请求场景下(如启动预加载、定时任务前处理),我们需要访问 Service / Model 等挂在 Context 上的对象,此时可使用app.createAnonymousContext()创建一个匿名的 Context 实例:

// app.js module.exports = app => { app.beforeStart(function* () { const ctx = app.createAnonymousContext(); // 在应用启动前预加载 yield ctx.service.posts.load(); }); }

从 lib/egg.js 的实现看,该方法会构造一份 mock 的 request 对象(默认 host 为127.0.0.1、method 为GET、url 为/),并允许传入req覆盖 headers、query、socket 等字段,最后通过createContext生成匿名上下文。测试用例 test/lib/egg.test.js 与 test/app/extend/application.test.js 均对该能力做了验证。

3.3 调度任务中的 Context

Schedule 中的每个任务都会以一个 Context 实例作为参数,方便在调度逻辑中直接调用服务:

// app/schedule/refresh.js exports.task = function* (ctx) { yield ctx.service.posts.refresh(); };

四、Request 与 Response:请求/响应级对象

  • Request请求级对象,继承自 Koa.Request,封装 Node.js 原生 HTTP Request,提供一组获取 HTTP 请求常用参数的辅助方法。
  • Response请求级对象,继承自 Koa.Response,封装 Node.js 原生 HTTP Response,提供一组设置 HTTP 响应的辅助方法。

4.1 获取方式与等价写法

在 Context 实例上可以通过ctx.requestctx.response获取当前请求的 Request 与 Response:

// app/controller/user.js module.exports = app => { return class UserController extends app.Controller { * fetch() { const { app, ctx } = this; const id = ctx.request.query.id; ctx.response.body = app.cache.get(id); } }; };

使用要点:

  • Koa 会把 Request 与 Response 的部分方法和属性代理到 Context 上(见 Koa.Context),因此ctx.request.query.idctx.query.id等价,ctx.response.body = ...ctx.body = ...等价。
  • 注意:获取 POST 请求体应使用ctx.request.body,而不是ctx.body

4.2 源码佐证:Egg 对 Request/Response 的扩展

Egg 在 app/extend/request.js 中为 Request 扩展了queries(数组形式的多值参数解析)、acceptJSON(判断客户端是否接受 JSON 响应,支持.json结尾路径、响应类型与 Accept 头三种判定,见 app/extend/request.js)等能力;在 app/extend/response.js 中扩展了length计算与响应类型工具;同时在 app/extend/context.js 通过 delegates 把acceptJSONqueriesiprealStatus等属性代理到 Context 上。这些扩展在 test/app/extend/request.test.js 与 test/app/extend/response.test.js 中有完整测试覆盖。

五、Controller:控制器基类

Egg 提供了 Controller 基类,并推荐所有 Controller 继承它。Controller 基类拥有以下属性:

属性说明
ctx当前请求的 Context 实例
appApplication 实例
config应用配置
service应用的所有 service
logger针对当前控制器封装的 logger 对象

在控制器文件中,有两种引用 Controller 基类的方式:

// app/controller/user.js // 方式一:从 app 实例获取(推荐) module.exports = app => { return class UserController extends app.Controller { // 实现 }; }; // 方式二:从 egg 模块获取 const egg = require('egg'); module.exports = class UserController extends egg.Controller { // 实现 };

从 lib/egg.js 可以看出,app.Controlleregg.Controller指向同一个BaseContextClass基类,两种写法完全等价,推荐方式一以避免在应用与框架间产生循环依赖问题。

六、Service:服务基类

Egg 提供 Service 基类并推荐所有 Service 继承。Service 基类的字段与 Controller 基类相同(ctxappconfigservicelogger),获取方式类似:

// app/service/user.js // 方式一:从 app 实例获取(推荐) module.exports = app => { return class UserService extends app.Service { // 实现 }; }; // 方式二:从 egg 模块获取 const egg = require('egg'); module.exports = class UserService extends egg.Service { // 实现 };

Service 的详细约定可参考 service.md。

七、Helper:通用工具函数容器

Helper 用于提供有用的工具函数:把常用的函数统一放入app/extend/helper.js,用 JavaScript 编写复杂逻辑,避免逻辑散落各处,同时更便于编写测试用例。Helper 本身是一个类,字段与 Controller 基类相同,且每次请求都会实例化,因此 Helper 上的所有函数都能拿到当前请求的 Context。

7.1 获取方式:ctx.helper 与模板中使用

在 Context 实例上通过ctx.helper获取当前请求的 Helper:

// app/controller/user.js module.exports = app => { return class UserController extends app.Controller { * fetch() { const { app, ctx } = this; const id = ctx.query.id; const user = app.cache.get(id); ctx.body = ctx.helper.formatUser(user); } }; };

此外,Helper 实例也可以在模板中访问,例如从模板中调用 security 插件提供的shtml方法:

// app/view/home.nj {{ helper.shtml(value) }}

7.2 自定义 Helper 方法

通过框架扩展可以自定义 Helper 方法(如上面示例中的formatUser):

// app/extend/helper.js module.exports = { formatUser(user) { return only(user, [ 'name', 'phone' ]); } };

7.3 源码佐证:Helper 的装载与内置方法

从 lib/application.js 可以看到,app.Helper会创建一个继承BaseContextClass的 Helper 类,并将${baseDir}/app/extend/helper.js中的方法装载到 Helper 原型上;app/extend/context.js 中的ctx.helpergetter 会在首次访问时new this.app.Helper(this)完成实例化。框架本身也在 app/extend/helper.js 内置了pathFor(name, params)(生成路由的路径)与urlFor(name, params)(生成带 host 的完整 URL)两个方法,可直接在控制器或模板中使用。

八、Config:配置对象

Egg 推荐遵循配置与代码分离的原则,把硬编码的业务参数放入配置文件;配置文件支持不同运行环境使用不同配置。框架、插件与应用层级的配置都可以通过 Config 对象访问。详细的配置机制请阅读 Configuration。

获取方式:

  • 通过app.config从 Application 实例获取;
  • 在 Controller、Service 或 Helper 实例中通过this.config获取。

框架启动时会把最终合并的配置 dump 到run/${type}_config.json(见 lib/egg.js),便于排查配置来源;同时dump.ignore(config/config.default.js)会在 dump 时忽略passwordkeys等敏感字段。

九、Logger:日志对象家族

Egg 内置了强大的 logger,可以很方便地把各种级别的日志输出到对应日志文件。每个 logger 对象提供 5 个级别的方法(注:原文列出的 4 个方法之外还有logger.debug(),共 5 个):

  • logger.debug()
  • logger.info()
  • logger.warn()
  • logger.error()

Egg 提供了多个 Logger 对象,下面介绍各自的获取方式与适用场景。

9.1 App Logger:app.logger

应用级日志,例如在启动阶段记录一些数据、记录业务相关信息,都可以使用 App Logger。对应日志文件为$HOME/logs/{appname}/{appname}-web(见 lib/egg.js)。

9.2 App CoreLogger:app.coreLogger

开发应用时不应通过 CoreLogger 打印日志——它供框架与插件打印应用级日志使用,便于与业务日志区分;CoreLogger 打印的日志会写入与 Logger 不同的文件(egg-web,见 lib/egg.js)。

9.3 Context Logger:ctx.logger

与请求强相关,会在日志前面带上当前请求的相关信息(如[$userId/$ip/$traceId/${cost}ms $method $url]),利用这些信息可以快速从日志中定位某个请求,并把一个请求内的所有日志串联起来。测试用例 test/lib/core/logger.test.js 展示了通过ctx.logger.error输出错误日志并落盘到common-error.log的完整链路。

9.4 Context CoreLogger:ctx.coreLogger

与 Context Logger 的区别在于:只有插件和框架会通过它打日志。

9.5 Controller Logger 与 Service Logger:this.logger

在 Controller 和 Service 实例中通过this.logger获取。它们本质上是 Context Logger,但会额外在日志中加入文件路径,便于定位日志打印位置。实现上,lib/core/base_context_class.js 为基类注入了基于BaseContextLoggerloggergetter,而 lib/core/base_context_logger.js 会在日志正文前追加[${pathName}]前缀。

十、Subscription:订阅模型基类

Subscription 是订阅模型,包括消息队列中的 consumer 或定时调度。egg 导出 Subscription 基类:

const Subscription = require('egg').Subscription; class Schedule extends Subscription { // 该方法必须实现 // subscribe 可以是 generator 函数或 async 函数 * subscribe() {} }

官方推荐插件开发者基于该模型实现能力,例如 Schedule 就是典型应用。通过它,可以把“订阅 / 消费”的通用模式抽象出来,让消息消费者与调度任务共享同一套生命周期约定。

十一、对象关系速查与实战建议

对象生命周期主要获取途径典型用途
Application应用级单例Loader 回调参数、ctx.appthis.app挂载全局方法/对象、启动逻辑
Context请求级中间件参数、this.ctxcreateAnonymousContext()请求信息封装、Service 访问
Request请求级ctx.request(部分属性代理到 ctx)读取请求参数
Response请求级ctx.response(部分属性代理到 ctx)设置响应
Controller请求级实例app.Controller/egg.Controller继承处理业务路由
Service请求级实例app.Service/egg.Service继承业务逻辑分层
Helper请求级实例ctx.helper通用工具函数
Config应用级app.configthis.config环境化配置读取
Logger应用级/请求级app.loggerctx.loggerthis.logger分级日志输出
Subscription模型基类egg.Subscription继承调度/消息消费

实战建议:

  1. 分清生命周期:Application 与 Config 是应用级、全局共享;Context、Request、Response、Controller、Service、Helper 是请求级,每次请求重新实例化——不要在请求级对象上缓存跨请求共享的全局状态。
  2. 优先使用推荐写法:Controller / Service 优先采用module.exports = app => class ... extends app.Controller/Service的写法,与 Loader 注入机制天然契合。
  3. 日志按场景选择:业务日志用app.logger/ctx.logger/this.logger;框架与插件日志用coreLogger系列,保持日志通道清晰隔离。
  4. 非请求场景善用匿名上下文:启动预加载、定时任务等场景通过app.createAnonymousContext()获取带 Service 能力的 Context,避免手动拼接。

这十类内置对象是 Egg 约定式开发的地基:理解它们的生命周期与获取方式,后续阅读 controller.md、service.md、middleware.md、extend.md 等文档时就能做到心中有数、随取随用。

  • 后端
  • Web框架

【免费下载链接】egg

🥚 Born to build better enterprise frameworks and apps with Node.js & Koa

项目地址:https://gitcode.com/gh_mirrors/egg11/egg
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 22:33:00

本地AI技能调度中枢:OpenClaw+Hermes架构原理与实战

1. 项目概述:这不是一个“AI工具合集”,而是一套可落地的本地化技能调度中枢“龙虾 Skill 技能库|OpenClawHermes 全集成 一键调用所有 AI 技能”——这个标题里没有一个词是虚的,但每一个词背后都藏着容易被忽略的工程现实。我从…

作者头像 李华
网站建设 2026/9/20 22:32:54

哈工大AI课程资料使用指南:从机器学习到强化学习的实战路径

简介:面向哈尔滨工业大学人工智能专业学子的课程学习与项目实践资料合集,覆盖机器学习、深度学习、自然语言处理、计算机视觉、强化学习等核心方向,适合本科日常自学、期末复习、考研复试准备以及课程设计/毕业设计参考。资源共348个文件&…

作者头像 李华
网站建设 2026/9/20 22:32:18

高斯模糊 RenderScript 效率低?Codex 走 TaoToken 对照 handleBit 排查

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华