Skip to content

Commit d73046b

Browse files
ottomaoxiaofeng.mxf
and
xiaofeng.mxf
authoredJan 24, 2024
feat: 优化中文文档表达 (#5290)
Co-authored-by: xiaofeng.mxf <xiaofeng.mxf@antgroup.com>
1 parent af2e543 commit d73046b

12 files changed

+641
-691
lines changed
 

‎site/docs/basics/app-start.zh-CN.md

+26-27
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,20 @@ title: 启动自定义
33
order: 12
44
---
55

6-
我们常常需要在应用启动期间进行一些初始化工作,等初始化完成后应用才可以启动成功,并开始对外提供服务。
6+
我们常常需要在应用启动期间进行一些初始化工作,待初始化完成后,应用才可以启动成功,并开始对外提供服务。
77

8-
框架提供了统一的入口文件(`app.js`)进行启动过程自定义,这个文件返回一个 Boot 类我们可以通过定义 Boot 类中的生命周期方法来执行启动应用过程中的初始化工作。
8+
框架提供了统一的入口文件(`app.js`)进行启动过程自定义。这个文件需要返回一个 Boot 类我们可以通过定义 Boot 类中的生命周期方法来执行启动应用过程中的初始化工作。
99

10-
框架提供了这些 [生命周期函数](../advanced/loader.md#life-cycles)供开发人员处理:
10+
框架提供了以下 [生命周期函数](../advanced/loader.md#life-cycles) 供开发人员处理:
11+
- 配置文件即将加载,这是最后动态修改配置的时机(`configWillLoad`);
12+
- 配置文件加载完成(`configDidLoad`);
13+
- 文件加载完成(`didLoad`);
14+
- 插件启动完毕(`willReady`);
15+
- worker 准备就绪(`didReady`);
16+
- 应用启动完成(`serverDidReady`);
17+
- 应用即将关闭(`beforeClose`)。
1118

12-
- 配置文件即将加载,这是最后动态修改配置的时机(`configWillLoad`
13-
- 配置文件加载完成(`configDidLoad`
14-
- 文件加载完成(`didLoad`
15-
- 插件启动完毕(`willReady`
16-
- worker 准备就绪(`didReady`
17-
- 应用启动完成(`serverDidReady`
18-
- 应用即将关闭(`beforeClose`
19-
20-
我们可以在 `app.js` 中定义这个 Boot 类,下面我们抽取几个在应用开发中常用的生命周期函数来举例:
19+
我们可以在 `app.js` 中定义这个 Boot 类。下面我们抽取几个在应用开发中常用的生命周期函数为例:
2120

2221
```js
2322
// app.js
@@ -27,8 +26,8 @@ class AppBootHook {
2726
}
2827

2928
configWillLoad() {
30-
// 此时 config 文件已经被读取并合并,但是还并未生效
31-
// 这是应用层修改配置的最后时机
29+
// 此时 config 文件已经被读取并合并,但还并未生效
30+
// 这是应用层修改配置的最后机会
3231
// 注意:此函数只支持同步调用
3332

3433
// 例如:参数中的密码是加密的,在此处进行解密
@@ -39,47 +38,47 @@ class AppBootHook {
3938
}
4039

4140
async didLoad() {
42-
// 所有的配置已经加载完毕
43-
// 可以用来加载应用自定义的文件,启动自定义的服务
41+
// 所有配置已经加载完毕
42+
// 可以用来加载应用自定义的文件,启动自定义服务
4443

45-
// 例如:创建自定义应用的示例
44+
// 例如:创建自定义应用的实例
4645
this.app.queue = new Queue(this.app.config.queue);
4746
await this.app.queue.init();
4847

49-
// 例如:加载自定义的目录
48+
// 例如:加载自定义目录
5049
this.app.loader.loadToContext(path.join(__dirname, 'app/tasks'), 'tasks', {
5150
fieldClass: 'tasksClasses',
5251
});
5352
}
5453

5554
async willReady() {
56-
// 所有的插件都已启动完毕,但是应用整体还未 ready
57-
// 可以做一些数据初始化等操作,这些操作成功才会启动应用
55+
// 所有插件已启动完毕,但应用整体尚未 ready
56+
// 可进行数据初始化等操作,这些操作成功后才启动应用
5857

5958
// 例如:从数据库加载数据到内存缓存
6059
this.app.cacheData = await this.app.model.query(QUERY_CACHE_SQL);
6160
}
6261

6362
async didReady() {
64-
// 应用已经启动完毕
63+
// 应用已启动完毕
6564

6665
const ctx = await this.app.createAnonymousContext();
6766
await ctx.service.Biz.request();
6867
}
6968

7069
async serverDidReady() {
71-
// http / https server 已启动,开始接受外部请求
72-
// 此时可以从 app.server 拿到 server 的实例
70+
// http/https 服务器已启动,开始接收外部请求
71+
// 此时可以从 app.server 获取 server 实例
7372

74-
this.app.server.on('timeout', (socket) => {
75-
// handle socket timeout
73+
this.app.server.on('timeout', socket => {
74+
// 处理 socket 超时
7675
});
7776
}
7877
}
7978

8079
module.exports = AppBootHook;
8180
```
8281

83-
**注意:在自定义生命周期函数中不建议做太耗时的操作,框架会有启动的超时检测**
82+
**注意:在自定义生命周期函数中,不建议进行耗时的操作,因为框架会有启动的超时检测**
8483

85-
如果你的 Egg 框架的生命周期函数是旧版本的,建议你升级到类方法模式;详情请查看[升级你的生命周期事件函数](../advanced/loader-update.md)
84+
如果你的 Egg 框架的生命周期函数是旧版本的,建议你将其升级到类方法模式;详情请查看[升级你的生命周期事件函数](../advanced/loader-update.md)

‎site/docs/basics/config.zh-CN.md

+31-34
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,16 @@ order: 4
55

66
框架提供了强大且可扩展的配置功能,可以自动合并应用、插件、框架的配置,按顺序覆盖,且可以根据环境维护不同的配置。合并后的配置可直接从 `app.config` 获取。
77

8-
配置的管理有多种方案,以下列一些常见的方案
8+
配置的管理有多种方案,以下列举一些常见的方案:
99

10-
1. 使用平台管理配置,应用构建时将当前环境的配置放入包内,启动时指定该配置。但应用就无法一次构建多次部署,而且本地开发环境想使用配置会变的很麻烦。
11-
1. 使用平台管理配置,在启动时将当前环境的配置通过环境变量传入,这是比较优雅的方式,但框架对运维的要求会比较高,需要部署平台支持,同时开发环境也有相同痛点。
12-
1. 使用代码管理配置,在代码中添加多个环境的配置,在启动时传入当前环境的参数即可。但无法全局配置,必须修改代码。
13-
14-
我们选择了最后一种配置方案,**配置即代码**,配置的变更也应该经过 review 后才能发布。应用包本身是可以部署在多个环境的,只需要指定运行环境即可。
10+
1. 使用平台管理配置,应用构建时将当前环境的配置放入包内,启动时指定该配置。但应用就无法一次构建多次部署,而且本地开发环境想使用配置会变得很麻烦。
11+
2. 使用平台管理配置,在启动时将当前环境的配置通过环境变量传入,这是比较优雅的方式,但框架对运维的要求会比较高,需要部署平台支持,同时开发环境也有相同的痛点。
12+
3. 使用代码管理配置,在代码中添加多个环境的配置,在启动时传入当前环境的参数即可。但无法全局配置,必须修改代码。
1513

14+
我们选择了最后一种配置方案,**配置即代码**,配置的变更也应该经过审核后才能发布。应用包本身是可以部署在多个环境的,只需要指定运行环境即可。
1615
### 多环境配置
1716

18-
框架支持根据环境来加载配置,定义多个环境的配置文件,具体环境请查看[运行环境配置](./env.md)
17+
框架支持根据环境来加载配置,定义多个环境的配置文件,具体环境请查看[运行环境配置](./env.md)
1918

2019
```
2120
config
@@ -27,11 +26,10 @@ config
2726

2827
`config.default.js` 为默认的配置文件,所有环境都会加载这个配置文件,一般也会作为开发环境的默认配置文件。
2928

30-
当指定 env 时会同时加载默认配置和对应的配置(具名配置)文件,具名配置和默认配置将合并(使用[extend2](https://www.npmjs.com/package/extend2)深拷贝)成最终配置,具名配置项会覆盖默认配置文件的同名配置。如 `prod` 环境会加载 `config.prod.js``config.default.js` 文件,`config.prod.js` 会覆盖 `config.default.js` 的同名配置。
31-
29+
当指定 `env` 时,会同时加载默认配置和对应的配置(具名配置)文件。具名配置和默认配置将合并(使用 [extend2](https://www.npmjs.com/package/extend2) 深拷贝)成最终配置,具名配置项会覆盖默认配置文件的同名配置。例如,`prod` 环境会加载 `config.prod.js``config.default.js` 文件,`config.prod.js` 会覆盖 `config.default.js` 的同名配置。
3230
### 配置写法
3331

34-
配置文件返回的是一个 object 对象,可以覆盖框架的一些配置,应用也可以将自己业务的配置放到这里方便管理。
32+
配置文件返回的是一个对象,可以覆盖框架的一些配置,应用也可以将自己业务的配置放到这里方便管理。
3533

3634
```js
3735
// 配置 logger 文件的目录,logger 默认配置由框架提供
@@ -42,7 +40,7 @@ module.exports = {
4240
};
4341
```
4442

45-
配置文件也可以简化的写成 `exports.key = value` 形式
43+
配置文件也可以简化地写成 `exports.key = value` 形式
4644

4745
```js
4846
exports.keys = 'my-cookie-secret-key';
@@ -51,7 +49,7 @@ exports.logger = {
5149
};
5250
```
5351

54-
配置文件也可以返回一个 function,可以接受 appInfo 参数
52+
配置文件也可以返回一个函数,该函数可以接受 `appInfo` 参数
5553

5654
```js
5755
// 将 logger 目录放到代码目录下
@@ -65,22 +63,22 @@ module.exports = (appInfo) => {
6563
};
6664
```
6765

68-
内置的 appInfo
66+
内置的 `appInfo` 属性包括:
6967

70-
| appInfo | 说明 |
71-
| ------- | ---------------------------------------------------------------------- |
72-
| pkg | package.json |
73-
| name | 应用名,同 pkg.name |
74-
| baseDir | 应用代码的目录 |
75-
| HOME | 用户目录,如 admin 账户为 /home/admin |
76-
| root | 应用根目录,只有在 local 和 unittest 环境下为 baseDir,其他都为 HOME。 |
68+
| appInfo | 说明 |
69+
| ------- | ------------------------------------------------------------ |
70+
| pkg | `package.json` 文件 |
71+
| name | 应用名称,同 `pkg.name` |
72+
| baseDir | 应用代码的目录 |
73+
| HOME | 用户目录,如 admin 账户为 `/home/admin` |
74+
| root | 应用根目录,`local``unittest` 环境下为 `baseDir`,其他都为 `HOME`|
7775

78-
`appInfo.root` 是一个优雅的适配,比如在服务器环境我们会使用 `/home/admin/logs` 作为日志目录,而本地开发时又不想污染用户目录,这样的适配就很好解决这个问题
76+
`appInfo.root` 是一个优雅的适配方案。例如,在服务器环境我们通常使用 `/home/admin/logs` 作为日志目录,而在本地开发时为了避免污染用户目录,我们需要一种优雅的适配方案,`appInfo.root` 正好解决了这个问题
7977

80-
请根据具体场合选择合适的写法,但请确保没有写出以下代码
78+
请根据具体场合选择合适的写法。但请确保没有完成以下代码
8179

8280
```js
83-
// config/config.default.js
81+
// 配置文件 config/config.default.js
8482
exports.someKeys = 'abc';
8583
module.exports = (appInfo) => {
8684
const config = {};
@@ -91,9 +89,9 @@ module.exports = (appInfo) => {
9189

9290
### 配置加载顺序
9391

94-
应用、插件、框架都可以定义这些配置,而且目录结构都是一致的,但存在优先级(应用 > 框架 > 插件),相对于此运行环境的优先级会更高。
92+
应用、插件、框架都可以定义这些配置,且目录结构都是一致的,但存在优先级(应用 > 框架 > 插件),相对于此运行环境的优先级会更高。
9593

96-
比如在 prod 环境加载一个配置的加载顺序如下,后加载的会覆盖前面的同名配置。
94+
比如在 prod 环境中加载一个配置的加载顺序如下,后加载的会覆盖前面的同名配置。
9795

9896
```
9997
-> 插件 config.default.js
@@ -104,11 +102,10 @@ module.exports = (appInfo) => {
104102
-> 应用 config.prod.js
105103
```
106104

107-
**注意:插件之间也会有加载顺序,但大致顺序类似,具体逻辑可[查看加载器](../advanced/loader.md)**
108-
105+
**注意**:插件之间也会有加载顺序,但大致顺序类似。具体逻辑可[查看加载器](../advanced/loader.md)
109106
### 合并规则
110107

111-
配置的合并使用 [extend2] 模块进行深度拷贝,[extend2] fork 自 [extend],处理数组时会存在差异
108+
配置的合并使用 `extend2` 模块进行深度拷贝,`extend2` 来源于 `extend`,但是在处理数组时的表现会有所不同
112109

113110
```js
114111
const a = {
@@ -125,14 +122,14 @@ extend(true, a, b);
125122

126123
### 配置结果
127124

128-
框架在启动时会把合并后的最终配置 dump 到 `run/application_config.json`(worker 进程)和 `run/agent_config.json`(agent 进程)中,可以用来分析问题
125+
框架在启动时会把合并后的最终配置输出到 `run/application_config.json`(worker 进程)和 `run/agent_config.json`(agent 进程)中,以供问题分析
129126

130-
配置文件中会隐藏一些字段,主要包括两类:
127+
配置文件中会隐藏以下两类字段:
131128

132-
- 如密码、密钥等安全字段,这里可以通过 `config.dump.ignore` 配置,必须是 [Set] 类型,查看[默认配置](https://github.com/eggjs/egg/blob/master/config/config.default.js)
133-
- 如函数、Buffer 等类型,`JSON.stringify` 后的内容特别大
129+
1. 安全字段,如密码、密钥等。这些字段通过 `config.dump.ignore` 属性进行配置,其类型必须是 [Set]。可参见[默认配置](https://github.com/eggjs/egg/blob/master/config/config.default.js)
130+
2. 非字符串化字段,如函数、Buffer 等。这些字段在 `JSON.stringify` 后所生成的内容容量很大。
134131

135-
还会生成 `run/application_config_meta.json`(worker 进程)和 `run/agent_config_meta.json`(agent 进程)文件,用来排查属性的来源,如
132+
此外,框架还会生成 `run/application_config_meta.json`(worker 进程)和 `run/agent_config_meta.json`(agent 进程)文件。这些文件用于排查配置属性的来源,例如:
136133

137134
```json
138135
{
@@ -142,6 +139,6 @@ extend(true, a, b);
142139
}
143140
```
144141

145-
[set]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
142+
[Set]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
146143
[extend]: https://github.com/justmoon/node-extend
147144
[extend2]: https://github.com/eggjs/extend2

‎site/docs/basics/controller.zh-CN.md

+256-270
Large diffs are not rendered by default.

‎site/docs/basics/env.zh-CN.md

+14-17
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ order: 3
99

1010
框架有两种方式指定运行环境:
1111

12-
1. 通过  `config/env` 文件指定,该文件的内容就是运行环境,如 `prod`。一般通过构建工具来生成这个文件。
12+
1. 通过 `config/env` 文件指定,该文件的内容就是运行环境,如 `prod`。一般通过构建工具来生成这个文件。
1313

14-
```
14+
```plaintext
1515
// config/env
1616
prod
1717
```
@@ -24,32 +24,29 @@ EGG_SERVER_ENV=prod npm start
2424

2525
## 应用内获取运行环境
2626

27-
框架提供了变量 `app.config.env` 来表示应用当前的运行环境。
28-
27+
框架提供了变量 `app.config.env`,来表示应用当前的运行环境。
2928
## 运行环境相关配置
3029

3130
不同的运行环境会对应不同的配置,具体请阅读 [Config 配置](./config.md)
31+
## `NODE_ENV` 的区别
3232

33-
## NODE_ENV 的区别
33+
很多 Node.js 应用会使用 `NODE_ENV` 来区分运行环境,但 `EGG_SERVER_ENV` 区分得更加精细。一般的项目开发流程包括本地开发环境、测试环境、生产环境等,除了本地开发环境和测试环境外,其他环境可统称为**服务器环境**。服务器环境的 `NODE_ENV` 应该为 `production`。而且 npm 也会使用这个变量,在应用部署时,一般不会安装 devDependencies,所以这个值也应该为 `production`
3434

35-
很多 Node.js 应用会使用 `NODE_ENV` 来区分运行环境,但 `EGG_SERVER_ENV` 区分得更加精细。一般的项目开发流程包括本地开发环境、测试环境、生产环境等,除了本地开发环境和测试环境外,其他环境可统称为**服务器环境**,服务器环境的 `NODE_ENV` 应该为 `production`。而且 npm 也会使用这个变量,在应用部署的时候一般不会安装 devDependencies,所以这个值也应该为 `production`
35+
框架默认支持的运行环境及映射关系(如果未指定 `EGG_SERVER_ENV`,会根据 `NODE_ENV` 来匹配)如下表所示:
3636

37-
框架默认支持的运行环境及映射关系(如果未指定 `EGG_SERVER_ENV` 会根据 `NODE_ENV` 来匹配)
38-
39-
| NODE_ENV | EGG_SERVER_ENV | 说明 |
40-
| ---------- | -------------- | ------------ |
41-
| | local | 本地开发环境 |
42-
| test | unittest | 单元测试 |
43-
| production | prod | 生产环境 |
37+
| `NODE_ENV` | `EGG_SERVER_ENV` | 说明 |
38+
|--------------|------------------|--------------|
39+
| (不设置) | local | 本地开发环境 |
40+
| test | unittest | 单元测试 |
41+
| production | prod | 生产环境 |
4442

4543
例如,当 `NODE_ENV``production``EGG_SERVER_ENV` 未指定时,框架会将 `EGG_SERVER_ENV` 设置成 `prod`
46-
4744
## 自定义环境
4845

49-
常规开发流程可能不仅仅只有以上几种环境,Egg 支持自定义环境来适应自己的开发流程
46+
Egg 框架支持开发者根据实际需要自定义开发环境
5047

51-
比如,要为开发流程增加集成测试环境 SIT。将 `EGG_SERVER_ENV` 设置成 `sit`(并建议设置 `NODE_ENV = production`),启动时会加载 `config/config.sit.js`,运行环境变量 `app.config.env` 会被设置成 `sit`
48+
假如你需要在开发流程中加入 SIT 集成测试环境,只需将环境变量 `EGG_SERVER_ENV` 设为 `sit`。同时,建议设置 `NODE_ENV``production`,这样在启动项目时,Egg 会加载 `config/config.sit.js` 配置文件,并将运行时环境的 `app.config.env` 设为 `sit`
5249

5350
## 与 Koa 的区别
5451

55-
在 Koa 中我们通过 `app.env` 来进行环境判断,`app.env` 默认的值是 `process.env.NODE_ENV`但是在 Egg(和基于 Egg 的框架)中,配置统一都放置在 `app.config` 上,所以我们需要通过 `app.config.env` 来区分环境`app.env` 不再使用
52+
在 Koa 中,我们通过 `app.env` 来判断运行环境,其默认值为 `process.env.NODE_ENV`然而在 Egg(及基于 Egg 的框架)中,配置统一放置于 `app.config`,因此需要通过 `app.config.env` 来区分环境。不再使用 `app.env`

‎site/docs/basics/extend.zh-CN.md

+38-38
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@ title: 框架扩展
33
order: 11
44
---
55

6-
框架提供了多种扩展点扩展自身的功能
6+
框架提供了多种扩展点,以扩展自身的功能
77

88
- Application
99
- Context
1010
- Request
1111
- Response
1212
- Helper
1313

14-
在开发中,我们既可以使用已有的扩展 API 来方便开发,也可以对以上对象进行自定义扩展,进一步加强框架的功能
14+
在开发中,我们既可以使用已有的扩展 API 来方便开发,也可以对以上对象进行自定义扩展,以进一步加强框架的功能
1515

1616
## Application
1717

@@ -20,19 +20,23 @@ order: 11
2020
### 访问方式
2121

2222
- `ctx.app`
23-
- Controller,Middleware,Helper,Service 中都可以通过 `this.app` 访问到 Application 对象,例如 `this.app.config` 访问配置对象。
24-
-`app.js` `app` 对象会作为第一个参数注入到入口函数中
23+
24+
`ctx.app` 提供了一种访问全局 `app` 对象的方式。
2525

26-
```js
27-
// app.js
28-
module.exports = (app) => {
29-
// 使用 app 对象
30-
};
31-
```
26+
- Controller,Middleware,Helper,Service 中都可以通过 `this.app` 访问到 Application 对象。例如,通过 `this.app.config` 可以访问配置对象。
27+
28+
-`app.js` 中,`app` 对象会作为第一个参数注入到入口函数中。
29+
30+
```js
31+
// app.js
32+
module.exports = app => {
33+
// 使用 app 对象
34+
};
35+
```
3236

3337
### 扩展方式
3438

35-
框架会把 `app/extend/application.js` 中定义的对象与 Koa Application 的 prototype 对象进行合并在应用启动时会基于扩展后的 prototype 生成 `app` 对象。
39+
框架会将 `app/extend/application.js` 中定义的对象与 Koa Application 的 prototype 对象进行合并在应用启动时会基于扩展后的 prototype 生成 `app` 对象。
3640

3741
#### 方法扩展
3842

@@ -49,31 +53,30 @@ module.exports = {
4953

5054
#### 属性扩展
5155

52-
一般来说属性的计算只需要进行一次,那么一定要实现缓存,否则在多次访问属性时会计算多次,这样会降低应用性能
56+
通常,属性的计算只需执行一次。因此,需要实现缓存以免多次访问属性时重复计算,这会降低应用性能
5357

54-
推荐的方式是使用 Symbol + Getter 的模式
58+
推荐使用 Symbol Getter 的模式实现属性缓存
5559

56-
例如,增加一个 `app.bar` 属性 Getter:
60+
例如,我们增加一个 `app.bar` 属性的 Getter:
5761

5862
```js
5963
// app/extend/application.js
6064
const BAR = Symbol('Application#bar');
6165

6266
module.exports = {
6367
get bar() {
64-
// this 就是 app 对象,在其中可以调用 app 上的其他方法,或访问属性
68+
// this app 对象,在其中可以调用 app 上的其他方法,或访问属性
6569
if (!this[BAR]) {
66-
// 实际情况肯定更复杂
70+
// 实际情况比这更复杂
6771
this[BAR] = this.config.xx + this.config.yy;
6872
}
6973
return this[BAR];
7074
},
7175
};
7276
```
73-
7477
## Context
7578

76-
Context 指的是 Koa 的请求上下文,这是 **请求级别** 的对象,每次请求生成一个 Context 实例,通常我们也简写成 `ctx`。在所有的文档中,Context 和 `ctx` 都是指 Koa 的上下文对象。
79+
Context 指的是 Koa 的请求上下文,这是请求级别的对象,每次请求生成一个 Context 实例,通常我们也简写成 `ctx`。在所有的文档中,Context 和 `ctx` 都是指 Koa 的上下文对象。
7780

7881
### 访问方式
7982

@@ -83,7 +86,7 @@ Context 指的是 Koa 的请求上下文,这是 **请求级别** 的对象,
8386

8487
### 扩展方式
8588

86-
框架会把 `app/extend/context.js` 中定义的对象与 Koa Context 的 prototype 对象进行合并,在处理请求时会基于扩展后的 prototype 生成 ctx 对象。
89+
框架会将 `app/extend/context.js` 中定义的对象与 Koa Context 的 prototype 对象进行合并,在处理请求时会基于扩展后的 prototype 生成 ctx 对象。
8790

8891
#### 方法扩展
8992

@@ -94,13 +97,13 @@ Context 指的是 Koa 的请求上下文,这是 **请求级别** 的对象,
9497
module.exports = {
9598
foo(param) {
9699
// this 就是 ctx 对象,在其中可以调用 ctx 上的其他方法,或访问属性
97-
},
100+
}
98101
};
99102
```
100103

101104
#### 属性扩展
102105

103-
一般来说属性的计算在同一次请求中只需要进行一次,那么一定要实现缓存,否则在同一次请求中多次访问属性时会计算多次,这样会降低应用性能。
106+
一般来说,属性的计算在同一次请求中只需要进行一次,那么一定要实现缓存,否则在同一次请求中多次访问属性时会计算多次,这样会降低应用性能。
104107

105108
推荐的方式是使用 Symbol + Getter 的模式。
106109

@@ -118,11 +121,10 @@ module.exports = {
118121
this[BAR] = this.get('x-bar');
119122
}
120123
return this[BAR];
121-
},
124+
}
122125
};
123126
```
124-
125-
## Request
127+
## Request 对象
126128

127129
Request 对象和 Koa 的 Request 对象相同,是 **请求级别** 的对象,它提供了大量请求相关的属性和方法供使用。
128130

@@ -132,13 +134,13 @@ Request 对象和 Koa 的 Request 对象相同,是 **请求级别** 的对象
132134
ctx.request;
133135
```
134136

135-
`ctx` 上的很多属性和方法都被代理到 `request` 对象上,对于这些属性和方法使用 `ctx` 和使用 `request` 去访问它们是等价的,例如 `ctx.url === ctx.request.url`
137+
`ctx` 上的很多属性和方法都被代理到 `request` 对象上,对于这些属性和方法使用 `ctx` 和使用 `request` 访问它们是等价的,例如 `ctx.url === ctx.request.url`
136138

137-
Koa 内置的代理 `request` 的属性和方法列表[Koa - Request aliases](http://koajs.com/#request-aliases)
139+
Koa 内置的代理 `request` 的属性和方法列表可参阅[Koa - Request aliases](http://koajs.com/#request-aliases)
138140

139141
### 扩展方式
140142

141-
框架会把 `app/extend/request.js` 中定义的对象与内置 `request` 的 prototype 对象进行合并,在处理请求时会基于扩展后的 prototype 生成 `request` 对象。
143+
框架会将 `app/extend/request.js` 中定义的对象与内置 `request` 的 prototype 对象进行合并,在处理请求时会基于扩展后的 prototype 生成 `request` 对象。
142144

143145
例如,增加一个 `request.foo` 属性 Getter:
144146

@@ -153,23 +155,23 @@ module.exports = {
153155

154156
## Response
155157

156-
Response 对象和 Koa 的 Response 对象相同,是 **请求级别** 的对象,它提供了大量响应相关的属性和方法供使用
158+
Response 对象和 Koa 的 Response 对象相同,是 **请求级别** 的对象,提供了众多响应相关的属性和方法供使用
157159

158160
### 访问方式
159161

160162
```js
161163
ctx.response;
162164
```
163165

164-
ctx 上的很多属性和方法都被代理到 `response` 对象上,对于这些属性和方法使用 `ctx` 和使用 `response` 去访问它们是等价的,例如 `ctx.status = 404``ctx.response.status = 404` 是等价的。
166+
`ctx` 上的许多属性和方法都代理到了 `response` 对象上,因此直接通过 `ctx` 访问这些属性和方法与通过 `response` 访问是等价的。例如,`ctx.status = 404``ctx.response.status = 404` 是等价的。
165167

166-
Koa 内置的代理 `response` 的属性和方法列表:[Koa Response aliases](http://koajs.com/#response-aliases)
168+
参考 Koa 官方文档中列出的内置代理 `response` 的属性和方法列表:[Koa Response aliases](http://koajs.com/#response-aliases)
167169

168170
### 扩展方式
169171

170-
框架会把 `app/extend/response.js` 中定义的对象与内置 `response` 的 prototype 对象进行合并,在处理请求时会基于扩展后的 prototype 生成 `response` 对象。
172+
框架会将 `app/extend/response.js` 中定义的对象与内置 `response` 的 prototype 对象合并,在处理请求时基于扩展后的 prototype 生成 `response` 对象。
171173

172-
例如,增加一个 `response.foo` 属性 setter:
174+
例如,要增加一个 `response.foo` 属性的 setter:
173175

174176
```js
175177
// app/extend/response.js
@@ -180,13 +182,13 @@ module.exports = {
180182
};
181183
```
182184

183-
就可以这样使用啦`this.response.foo = 'bar';`
185+
现在可以这样使用`this.response.foo = 'bar';`
184186

185187
## Helper
186188

187189
Helper 函数用来提供一些实用的 utility 函数。
188190

189-
它的作用在于我们可以将一些常用的动作抽离在 helper.js 里面成为一个独立的函数,这样可以用 JavaScript 来写复杂的逻辑,避免逻辑分散各处。另外还有一个好处是 Helper 这样一个简单的函数,可以让我们更容易编写测试用例。
191+
它的作用在于我们可以将一些常用的动作抽离在 `helper.js` 里面成为一个独立的函数,这样可以用 JavaScript 来写复杂的逻辑,避免逻辑分散各处。另外还有一个好处是 Helper 这样一个简单的函数,可以让我们更容易编写测试用例。
190192

191193
框架内置了一些常用的 Helper 函数。我们也可以编写自定义的 Helper 函数。
192194

@@ -222,7 +224,7 @@ module.exports = {
222224

223225
## 按照环境进行扩展
224226

225-
另外,还可以根据环境进行有选择的扩展,例如,只在 unittest 环境中提供 `mockXX()` 方法以便进行 mock 方便测试
227+
`unittest` 环境中,你可以选择性地扩展应用程序。例如,只在 `unittest` 现场提供 `mockXX()` 方法,便于进行 mock 测试
226228

227229
```js
228230
// app/extend/application.unittest.js
@@ -231,6 +233,4 @@ module.exports = {
231233
};
232234
```
233235

234-
这个文件只会在 unittest 环境加载。
235-
236-
同理,对于 Application,Context,Request,Response,Helper 都可以使用这种方式针对某个环境进行扩展,更多参见[运行环境](./env.md)
236+
这个文件只会在 `unittest` 环境加载。同理,Application、Context、Request、Response 和 Helper 都可以使用这种方式针对某个特定环境进行扩展。更多信息,请参阅[运行环境](./env.md)

‎site/docs/basics/middleware.zh-CN.md

+30-36
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ order: 5
99

1010
### 写法
1111

12-
我们先来通过编写一个简单的 gzip 中间件,来看看中间件的写法
12+
我们首先来通过编写一个简单的 gzip 中间件,了解中间件的写法
1313

1414
```js
1515
// app/middleware/gzip.js
@@ -19,7 +19,7 @@ const zlib = require('zlib');
1919
async function gzip(ctx, next) {
2020
await next();
2121

22-
// 后续中间件执行完成后将响应体转换成 gzip
22+
// 后续中间件执行完成后,将响应体转换成 gzip
2323
let body = ctx.body;
2424
if (!body) return;
2525
if (isJSON(body)) body = JSON.stringify(body);
@@ -36,12 +36,12 @@ async function gzip(ctx, next) {
3636

3737
### 配置
3838

39-
一般来说中间件也会有自己的配置。在框架中,一个完整的中间件是包含了配置处理的。我们约定一个中间件是一个放置在 `app/middleware` 目录下的单独文件它需要 exports 一个普通的 function,接受两个参数:
39+
一般来说,中间件也会有自己的配置。在框架中,一个完整的中间件包含了配置处理。我们约定一个中间件是一个放置于 `app/middleware` 目录下的单独文件它需要 `exports` 一个普通的函数,接受两个参数:
4040

41-
- options: 中间件的配置项,框架会将 `app.config[${middlewareName}]` 传递进来。
42-
- app: 当前应用 Application 的实例。
41+
- `options`中间件的配置项,框架会将 `app.config[${middlewareName}]` 传递进来。
42+
- `app`当前应用 `Application` 的实例。
4343

44-
我们将上面的 gzip 中间件做一个简单的优化,让它支持指定只有当 body 大于配置的 threshold 时才进行 gzip 压缩,我们要在 `app/middleware` 目录下新建一个文件 `gzip.js`
44+
下面我们对上文中的 gzip 中间件做一个简单的优化,使其支持指定只有当体积大于配置的 `threshold` 时才进行 gzip 压缩。我们在 `app/middleware` 目录下新建 `gzip.js` 文件。
4545

4646
```js
4747
// app/middleware/gzip.js
@@ -52,7 +52,7 @@ module.exports = (options) => {
5252
return async function gzip(ctx, next) {
5353
await next();
5454

55-
// 后续中间件执行完成后将响应体转换成 gzip
55+
// 后续中间件执行完成后,将响应体转换成 gzip
5656
let body = ctx.body;
5757
if (!body) return;
5858

@@ -69,7 +69,6 @@ module.exports = (options) => {
6969
};
7070
};
7171
```
72-
7372
## 使用中间件
7473

7574
中间件编写完成后,我们还需要手动挂载,支持以下方式:
@@ -87,8 +86,8 @@ module.exports = {
8786

8887
// 配置 gzip 中间件的配置
8988
gzip: {
90-
threshold: 1024, // 小于 1k 的响应体不压缩
91-
},
89+
threshold: 1024 // 小于 1k 的响应体不压缩
90+
}
9291
};
9392
```
9493

@@ -100,14 +99,14 @@ module.exports = {
10099

101100
```js
102101
// app.js
103-
module.exports = (app) => {
102+
module.exports = app => {
104103
// 在中间件最前面统计请求时间
105104
app.config.coreMiddleware.unshift('report');
106105
};
107106

108107
// app/middleware/report.js
109108
module.exports = () => {
110-
return async function (ctx, next) {
109+
return async function(ctx, next) {
111110
const startTime = Date.now();
112111
await next();
113112
// 上报请求时间
@@ -118,21 +117,20 @@ module.exports = () => {
118117

119118
应用层定义的中间件(`app.config.appMiddleware`)和框架默认中间件(`app.config.coreMiddleware`)都会被加载器加载,并挂载到 `app.middleware` 上。
120119

121-
### router 中使用中间件
120+
### router 中使用中间件
122121

123122
以上两种方式配置的中间件是全局的,会处理每一次请求。
124123
如果你只想针对单个路由生效,可以直接在 `app/router.js` 中实例化和挂载,如下:
125124

126125
```js
127-
module.exports = (app) => {
126+
module.exports = app => {
128127
const gzip = app.middleware.gzip({ threshold: 1024 });
129128
app.router.get('/needgzip', gzip, app.controller.handler);
130129
};
131130
```
132-
133131
## 框架默认中间件
134132

135-
除了应用层加载中间件之外,框架自身和其他的插件也会加载许多中间件。所有的这些自带中间件的配置项都通过在配置中修改中间件同名配置项进行修改,例如[框架自带的中间件](https://github.com/eggjs/egg/tree/master/app/middleware)中有一个 bodyParser 中间件(框架的加载器会将文件名中的各种分隔符都修改成驼峰形式的变量名),我们想要修改 bodyParser 的配置,只需要在 `config/config.default.js` 中编写
133+
除了应用层加载中间件之外,框架自身和其他插件也会加载许多中间件。所有这些自带中间件的配置项都可以通过修改配置文件中的同名配置项来进行更改。例如,框架自带的中间件列表中有一个名为 `bodyParser` 的中间件(框架的加载器会将文件名中的分隔符都转换为驼峰形式的变量名)。如果我们想要修改 `bodyParser` 的配置,只需要在 `config/config.default.js` 中编写如下内容:
136134

137135
```js
138136
module.exports = {
@@ -142,19 +140,18 @@ module.exports = {
142140
};
143141
```
144142

145-
**注意:框架和插件加载的中间件会在应用层配置的中间件之前,框架默认中间件不能被应用层中间件覆盖,如果应用层有自定义同名中间件,在启动时会报错。**
146-
143+
**注意:框架和插件加载的中间件会在应用层配置的中间件之前被加载。框架默认中间件不能被应用层中间件覆盖。如果应用层有自定义同名中间件,启动时将会报错。**
147144
## 使用 Koa 的中间件
148145

149-
在框架里面可以非常容易的引入 Koa 中间件生态。
146+
在框架里面可以非常容易地引入 Koa 中间件生态。
150147

151-
[koa-compress](https://github.com/koajs/compress) 为例,在 Koa 中使用时:
148+
[`koa-compress`](https://github.com/koajs/compress) 为例,在 Koa 中使用时:
152149

153150
```js
154151
const koa = require('koa');
155152
const compress = require('koa-compress');
156153

157-
const app = koa();
154+
const app = new koa();
158155

159156
const options = { threshold: 2048 };
160157
app.use(compress(options));
@@ -164,7 +161,7 @@ app.use(compress(options));
164161

165162
```js
166163
// app/middleware/compress.js
167-
// koa-compress 暴露的接口(`(options) => middleware`)和框架对中间件要求一致
164+
// koa-compress 暴露的接口`(options) => middleware`和框架对中间件要求一致
168165
module.exports = require('koa-compress');
169166
```
170167

@@ -196,18 +193,17 @@ module.exports = (options, app) => {
196193
return webpackMiddleware(options.compiler, options.others);
197194
};
198195
```
199-
200196
## 通用配置
201197

202198
无论是应用层加载的中间件还是框架自带中间件,都支持几个通用的配置项:
203199

204-
- enable:控制中间件是否开启。
205-
- match:设置只有符合某些规则的请求才会经过这个中间件。
206-
- ignore:设置符合某些规则的请求不经过这个中间件。
200+
- `enable`:控制中间件是否开启。
201+
- `match`:设置只有符合某些规则的请求才会经过这个中间件。
202+
- `ignore`:设置符合某些规则的请求不经过这个中间件。
207203

208204
### enable
209205

210-
如果我们的应用并不需要默认的 bodyParser 中间件来进行请求体的解析,此时我们可以通过配置 enable 为 false 来关闭它
206+
如果我们的应用并不需要默认的 `bodyParser` 中间件来进行请求体的解析,此时我们可以通过配置 `enable``false` 来关闭它
211207

212208
```js
213209
module.exports = {
@@ -219,9 +215,9 @@ module.exports = {
219215

220216
### match 和 ignore
221217

222-
match 和 ignore 支持的参数都一样,只是作用完全相反,match 和 ignore 不允许同时配置。
218+
`match``ignore` 支持的参数都一样,只是作用完全相反,`match``ignore` 不允许同时配置。
223219

224-
如果我们想让 gzip 只针对 `/static` 前缀开头的 url 请求开启,我们可以配置 match 选项
220+
如果我们想让 `gzip` 只针对 `/static` 前缀开头的 url 请求开启,我们可以配置 `match` 选项
225221

226222
```js
227223
module.exports = {
@@ -231,24 +227,22 @@ module.exports = {
231227
};
232228
```
233229

234-
match 和 ignore 支持多种类型的配置方式
230+
`match``ignore` 支持多种类型的配置方式
235231

236-
1. 字符串:当参数为字符串类型时,配置的是一个 url 的路径前缀,所有以配置的字符串作为前缀的 url 都会匹配上。
237-
当然,你也可以直接使用字符串数组。
232+
1. 字符串:当参数为字符串类型时,配置的是一个 url 的路径前缀,所有以配置的字符串作为前缀的 url 都会匹配上。当然,你也可以直接使用字符串数组。
238233
2. 正则:当参数为正则时,直接匹配满足正则验证的 url 的路径。
239-
3. 函数:当参数为一个函数时,会将请求上下文传递给这个函数,最终取函数返回的结果(true/false)来判断是否匹配。
234+
3. 函数:当参数为一个函数时,会将请求上下文传递给这个函数,最终取函数返回的结果(`true`/`false`)来判断是否匹配。
240235

241236
```js
242237
module.exports = {
243238
gzip: {
244239
match(ctx) {
245-
// 只有 ios 设备才开启
240+
// 只有 iOS 设备才开启
246241
const reg = /iphone|ipad|ipod/i;
247242
return reg.test(ctx.get('user-agent'));
248243
},
249244
},
250245
};
251246
```
252247

253-
有关更多的 match 和 ignore 配置情况,详见
254-
[egg-path-matching](https://github.com/eggjs/egg-path-matching).
248+
有关更多的 `match``ignore` 配置情况,详见 [egg-path-matching](https://github.com/eggjs/egg-path-matching)

‎site/docs/basics/objects.zh-CN.md

+71-75
Large diffs are not rendered by default.

‎site/docs/basics/plugin.zh-CN.md

+29-34
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,14 @@ title: 插件
33
order: 9
44
---
55

6-
插件机制是我们框架的一大特色。它不但可以保证框架核心的足够精简、稳定、高效,还可以促进业务逻辑的复用,生态圈的形成。有人可能会问了
6+
插件机制是我们框架的一大特色。它不但可以保证框架核心的足够精简、稳定、高效,还可以促进业务逻辑的复用,生态圈的形成。有人可能会问了
77

8-
- Koa 已经有了中间件的机制,为啥还要插件呢
9-
- 中间件、插件、应用它们之间是什么关系,有什么区别
10-
- 我该怎么使用一个插件
8+
- Koa 已经有了中间件的机制,为什么还要插件呢
9+
- 中间件、插件、应用之间是什么关系,它们之间有什么区别
10+
- 我该如何使用一个插件
1111
- 如何编写一个插件?
12-
- ...
13-
14-
接下来我们就来逐一讨论
1512

13+
接下来我们就来逐一讨论。
1614
## 为什么要插件
1715

1816
我们在使用 Koa 中间件过程中发现了下面一些问题:
@@ -25,28 +23,27 @@ order: 9
2523

2624
### 中间件、插件、应用的关系
2725

28-
一个插件其实就是一个迷你的应用,和应用(app)几乎一样:
26+
一个插件其实就是一个迷你的应用,和应用(app)几乎一样:
2927

3028
- 它包含了 [Service](./service.md)[中间件](./middleware.md)[配置](./config.md)[框架扩展](./extend.md)等等。
3129
- 它没有独立的 [Router](./router.md)[Controller](./controller.md)
32-
- 它没有 `plugin.js`只能声明跟其他插件的依赖,而**不能决定**其他插件的开启与否。
30+
- 它没有 `plugin.js`只能声明和其他插件的依赖,而**不能决定**其他插件的开启与否。
3331

3432
他们的关系是:
3533

3634
- 应用可以直接引入 Koa 的中间件。
37-
- 当遇到上一节提到的场景时,则应用需引入插件
35+
- 当遇到上一节提到的场景时,应用需引入插件
3836
- 插件本身可以包含中间件。
3937
- 多个插件可以包装为一个[上层框架](../advanced/framework.md)
40-
4138
## 使用插件
4239

43-
插件一般通过 npm 模块的方式进行复用:
40+
插件通常通过 npm 模块的方式进行复用:
4441

4542
```bash
4643
$ npm i egg-mysql --save
4744
```
4845

49-
**注意:我们建议通过 `^` 的方式引入依赖,并且强烈不建议锁定版本。**
46+
**注意:我们推荐通过 `^` 的方式引入依赖,并且强烈不建议锁定版本。**
5047

5148
```json
5249
{
@@ -56,7 +53,7 @@ $ npm i egg-mysql --save
5653
}
5754
```
5855

59-
然后需要在应用或框架的 `config/plugin.js` 中声明:
56+
接着,需要在应用或框架的 `config/plugin.js` 中声明:
6057

6158
```js
6259
// config/plugin.js
@@ -67,7 +64,7 @@ exports.mysql = {
6764
};
6865
```
6966

70-
就可以直接使用插件提供的功能
67+
这样就可以直接使用插件提供的功能
7168

7269
```js
7370
app.mysql.query(sql, values);
@@ -79,23 +76,23 @@ app.mysql.query(sql, values);
7976

8077
- `{Boolean} enable` - 是否开启此插件,默认为 true
8178
- `{String} package` - `npm` 模块名称,通过 `npm` 模块形式引入插件
82-
- `{String} path` - 插件绝对路径, package 配置互斥
83-
- `{Array} env` - 只有在指定运行环境才能开启,会覆盖插件自身 `package.json` 中的配置
79+
- `{String} path` - 插件绝对路径, package 配置互斥
80+
- `{Array} env` - 只有在指定运行环境才能开启,会覆盖该插件自身 `package.json` 中的配置
8481

8582
### 开启和关闭
8683

87-
在上层框架内部内置的插件,应用在使用时就不用配置 package 或者 path,只需要指定 enable 与否
84+
在上层框架内置的插件,应用在使用时,可以不配置 package 或者 path,只需指定 enable 即可
8885

8986
```js
90-
// 对于内置插件,可以用下面的简洁方式开启或关闭
87+
// 对于内置插件,可采用以下简洁方式开启或关闭
9188
exports.onerror = false;
9289
```
9390

9491
### 根据环境配置
9592

96-
同时,我们还支持 `plugin.{env}.js` 这种模式,会根据[运行环境](../basics/env.md)加载插件配置。
93+
同时,我们还支持 `plugin.{env}.js` 的模式,会根据[运行环境](../basics/env.md)加载插件配置。
9794

98-
比如定义了一个开发环境使用的插件 `egg-dev`只希望在本地环境加载,可以安装到 `devDependencies`
95+
比如,如果定义了一个只在开发环境使用的插件 `egg-dev`希望只在本地环境加载,可以将其安装到 `devDependencies`
9996

10097
```js
10198
// npm i egg-dev --save-dev
@@ -107,7 +104,7 @@ exports.onerror = false;
107104
}
108105
```
109106

110-
然后在 `plugin.local.js` 中声明:
107+
接下来,在 `plugin.local.js` 中声明:
111108

112109
```js
113110
// config/plugin.local.js
@@ -117,18 +114,18 @@ exports.dev = {
117114
};
118115
```
119116

120-
这样在生产环境可以 `npm i --production` 不需要下载 `egg-dev` 的包了
117+
这样,在生产环境下执行 `npm i --production` 时,就不需要下载 `egg-dev` 包了
121118

122119
**注意:**
123120

124-
- 不存在 `plugin.default.js`
125-
- **只能在应用层使用,在框架层请勿使用**
121+
- `plugin.default.js` 不存在
122+
- **只能在应用层使用,框架层请勿使用**
126123

127124
### package 和 path
128125

129126
- `package``npm` 方式引入,也是最常见的引入方式
130-
- `path` 是绝对路径引入,如应用内部抽了一个插件,但还没达到开源发布独立 `npm` 的阶段,或者是应用自己覆盖了框架的一些插件
131-
- 关于这两种方式的使用场景,可以参见[渐进式开发](../intro/progressive.md)
127+
- `path` 是绝对路径引入,例如应用内部提取了一个插件,但尚未发布至 npm;或者是应用自行改写了框架的某些插件
128+
- 关于这两种方式的使用场景,可参见[渐进式开发](../intro/progressive.md)文档
132129

133130
```js
134131
// config/plugin.js
@@ -138,10 +135,9 @@ exports.mysql = {
138135
path: path.join(__dirname, '../lib/plugin/egg-mysql'),
139136
};
140137
```
141-
142138
## 插件配置
143139

144-
插件一般会包含自己的默认配置应用开发者可以在 `config.default.js` 覆盖对应的配置
140+
插件一般会包含自己的默认配置应用开发者可以在 `config.default.js` 中覆盖对应的配置
145141

146142
```js
147143
// config/config.default.js
@@ -151,13 +147,12 @@ exports.mysql = {
151147
port: '3306',
152148
user: 'test_user',
153149
password: 'test_password',
154-
database: 'test',
155-
},
150+
database: 'test'
151+
}
156152
};
157153
```
158154

159-
具体合并规则可以参见[配置](./config.md)
160-
155+
具体的合并规则可以参见[配置](./config.md)
161156
## 插件列表
162157

163158
- 框架默认内置了企业级应用[常用的插件](https://eggjs.org/zh-cn/plugins/)
@@ -173,7 +168,7 @@ exports.mysql = {
173168
- [static](https://github.com/eggjs/egg-static) 静态服务器
174169
- [jsonp](https://github.com/eggjs/egg-jsonp) jsonp 支持
175170
- [view](https://github.com/eggjs/egg-view) 模板引擎
176-
- 更多社区的插件可以 GitHub 搜索 [egg-plugin](https://github.com/topics/egg-plugin)
171+
- 更多社区的插件可以在 GitHub 上搜索 [egg-plugin](https://github.com/topics/egg-plugin)
177172

178173
## 如何开发一个插件
179174

‎site/docs/basics/router.zh-CN.md

+43-51
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@ title: 路由(Router)
33
order: 6
44
---
55

6-
Router 主要用来描述请求 URL 和具体承担执行动作的 Controller 的对应关系,
7-
框架约定了 `app/router.js` 文件用于统一所有路由规则。
8-
9-
通过统一的配置,我们可以避免路由规则逻辑散落在多个地方,从而出现未知的冲突,集中在一起我们可以更方便的来查看全局的路由规则。
6+
Router 主要用来描述请求 URL 和具体承担执行动作的 Controller 的对应关系,框架约定了 `app/router.js` 文件用于统一所有路由规则。
107

8+
通过统一的配置,我们可以避免路由规则逻辑散落在多个地方,从而出现未知的冲突。集中在一起,我们可以更方便地来查看全局的路由规则。
119
## 如何定义 Router
1210

1311
- `app/router.js` 里面定义 URL 路由规则
@@ -35,7 +33,6 @@ class UserController extends Controller {
3533
```
3634

3735
这样就完成了一个最简单的 Router 定义,当用户执行 `GET /user/123``user.js` 这个里面的 info 方法就会执行。
38-
3936
## Router 详细定义说明
4037

4138
下面是路由的完整定义,参数可以根据场景的不同,自由选择:
@@ -47,37 +44,37 @@ router.verb('path-match', middleware1, ..., middlewareN, app.controller.action);
4744
router.verb('router-name', 'path-match', middleware1, ..., middlewareN, app.controller.action);
4845
```
4946

50-
路由完整定义主要包括 5 个主要部分:
51-
52-
- verb - 用户触发动作,支持 getpost 等所有 HTTP 方法,后面会通过示例详细说明。
53-
- router.head - HEAD
54-
- router.options - OPTIONS
55-
- router.get - GET
56-
- router.put - PUT
57-
- router.post - POST
58-
- router.patch - PATCH
59-
- router.delete - DELETE
60-
- router.del - 由于 delete 是一个保留字,所以提供了一个 delete 方法的别名。
61-
- router.redirect - 可以对 URL 进行重定向处理,比如我们最经常使用的可以把用户访问的根目录路由到某个主页。
62-
- router-name 给路由设定一个别名,可以通过 Helper 提供的辅助函数 `pathFor``urlFor` 来生成 URL。(可选)
63-
- path-match - 路由 URL 路径。
64-
- middleware1 - 在 Router 里面可以配置多个 Middleware。(可选)
65-
- controller - 指定路由映射到的具体的 controller 上,controller 可以有两种写法:
66-
- `app.controller.user.fetch` - 直接指定一个具体的 controller
67-
- `'user.fetch'` - 可以简写为字符串形式
47+
路由的完整定义主要包括以下五个主要部分:
48+
49+
- `verb`用户触发动作,支持 getpost 等所有 HTTP 方法,后面会通过示例详细说明。
50+
- `router.head`HEAD
51+
- `router.options`OPTIONS
52+
- `router.get`GET
53+
- `router.put`PUT
54+
- `router.post`POST
55+
- `router.patch`PATCH
56+
- `router.delete`DELETE
57+
- `router.del`由于 delete 是一个保留字,所以提供了一个 delete 方法的别名。
58+
- `router.redirect`可以对 URL 进行重定向处理,比如我们最经常使用的可以把用户访问的根目录路由到某个主页。
59+
- `router-name`给路由设定一个别名,可以通过 Helper 提供的辅助函数 `pathFor``urlFor` 来生成 URL。(可选)
60+
- `path-match`路由 URL 路径。
61+
- `middlewareN`在 Router 里面可以配置多个 Middleware。(可选)
62+
- `controller`:指定路由映射到的具体 controller 上,controller 可以有两种写法:
63+
- `app.controller.user.fetch`直接指定一个具体的 controller
64+
- `'user.fetch'`可以简写为字符串形式
6865

6966
### 注意事项
7067

71-
- 在 Router 定义中, 可以支持多个 Middleware 串联执行
68+
- 在 Router 定义中,可以支持多个 Middleware 串联执行
7269
- Controller 必须定义在 `app/controller` 目录中。
73-
- 一个文件里面也可以包含多个 Controller 定义,在定义路由的时候,可以通过 `${fileName}.${functionName}` 的方式指定对应的 Controller。
74-
- Controller 支持子目录,在定义路由的时候,可以通过 `${directoryName}.${fileName}.${functionName}` 的方式指定对应的 Controller。
70+
- 一个文件里面也可以包含多个 Controller 定义,在定义路由时,可以通过 `${fileName}.${functionName}` 的方式指定对应的 Controller。
71+
- Controller 支持子目录,在定义路由时,可以通过 `${directoryName}.${fileName}.${functionName}` 的方式指定对应的 Controller。
7572

76-
下面是一些路由定义的方式
73+
以下是一些路由定义的方式
7774

7875
```js
7976
// app/router.js
80-
module.exports = (app) => {
77+
module.exports = app => {
8178
const { router, controller } = app;
8279
router.get('/home', controller.home);
8380
router.get('/user/:id', controller.user.page);
@@ -89,20 +86,18 @@ module.exports = (app) => {
8986

9087
### RESTful 风格的 URL 定义
9188

92-
如果想通过 RESTful 的方式来定义路由,
93-
我们提供了 `app.router.resources('routerName', 'pathMatch', controller)` 快速在一个路径上生成 [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) 路由结构。
89+
如果想用 RESTful 的方式定义路由,我们提供了 `app.router.resources('routerName', 'pathMatch', controller)` 方法,快速在一个路径上生成 [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) 路由结构。
9490

9591
```js
9692
// app/router.js
97-
module.exports = (app) => {
93+
module.exports = app => {
9894
const { router, controller } = app;
9995
router.resources('posts', '/api/posts', controller.posts);
10096
router.resources('users', '/api/v1/users', controller.v1.users); // app/controller/v1/users.js
10197
};
10298
```
10399

104-
上面代码就在 `/posts` 路径上部署了一组 CRUD 路径结构,对应的 Controller 为 `app/controller/posts.js` 接下来,
105-
你只需要在 `posts.js` 里面实现对应的函数就可以了。
100+
上述代码就在 `/posts` 路径上部署了一组 CRUD 路径结构,对应的 Controller 为 `app/controller/posts.js`。接下来,只需在 `posts.js` 里面实现对应的函数即可。
106101

107102
| Method | Path | Route Name | Controller.Action |
108103
| ------ | --------------- | ---------- | ----------------------------- |
@@ -131,11 +126,10 @@ exports.update = async () => {};
131126
exports.destroy = async () => {};
132127
```
133128

134-
如果我们不需要其中的某几个方法,可以不用在 `posts.js` 里面实现,这样对应 URL 路径也不会注册到 Router。
135-
129+
如果我们不需要其中的某些方法,可以省略在 `posts.js` 里面的实现,这样对应的 URL 路径也不会注册到 Router 中。
136130
## router 实战
137131

138-
下面通过更多实际的例子,来说明 router 的用法。
132+
下面通过更多实际的例子,来说明 `router` 的用法。
139133

140134
### 参数获取
141135

@@ -173,7 +167,7 @@ exports.info = async (ctx) => {
173167

174168
#### 复杂参数的获取
175169

176-
路由里面也支持定义正则,可以更加灵活的获取参数
170+
路由里面也支持定义正则,可以更加灵活地获取参数
177171

178172
```js
179173
// app/router.js
@@ -186,8 +180,8 @@ module.exports = (app) => {
186180

187181
// app/controller/package.js
188182
exports.detail = async (ctx) => {
189-
// 如果请求 URL 被正则匹配, 可以按照捕获分组的顺序,从 ctx.params 中获取。
190-
// 按照下面的用户请求,`ctx.params[0]` 的 内容就是 `egg/1.0.0`
183+
// 如果请求 URL 被正则匹配,可以按照捕获分组的顺序,从 ctx.params 中获取。
184+
// 按照下面的用户请求,`ctx.params[0]` 的内容就是 `egg/1.0.0`
191185
ctx.body = `package:${ctx.params[0]}`;
192186
};
193187

@@ -213,17 +207,15 @@ exports.post = async (ctx) => {
213207

214208
> 附:
215209
216-
> 这里直接发起 POST 请求会**报错**:'secret is missing'。错误信息来自 [koa-csrf/index.js#L69](https://github.com/koajs/csrf/blob/2.5.0/index.js#L69)
217-
218-
> **原因**:框架内部针对表单 POST 请求均会验证 CSRF 的值,因此我们在表单提交时,请带上 CSRF key 进行提交,可参考[安全威胁 csrf 的防范](https://eggjs.org/zh-cn/core/security.html#安全威胁csrf的防范)
210+
> 这里直接发起 POST 请求会**报错**:'secret is missing'。错误信息来源于 [koa-csrf/index.js#L69](https://github.com/koajs/csrf/blob/2.5.0/index.js#L69)
219211
220-
> **注意**上面的校验是因为框架中内置了安全插件 [egg-security](https://github.com/eggjs/egg-security),提供了一些默认的安全实践,并且框架的安全插件是默认开启的,如果需要关闭其中一些安全防范,直接设置该项的 enable 属性为 false 即可
212+
> **原因**框架内部针对表单 POST 请求均会验证 CSRF 的值,因此我们在表单提交时,需要带上 CSRF key 进行提交。具体可参考[安全威胁 CSRF 的防范](https://eggjs.org/zh-cn/core/security.html#安全威胁csrf的防范)
221213
222-
> 「除非清楚的确认后果,否则不建议擅自关闭安全插件提供的功能。」
214+
> **注意**:上述校验是因为框架中内置了安全插件 [egg-security](https://github.com/eggjs/egg-security),提供了一些默认的安全实践,并且框架的安全插件默认是开启的。如果需要关闭一些安全防范,直接设置相应选项的 `enable` 属性为 `false` 即可。
223215
224-
> 这里在写例子的话可临时在 `config/config.default.js` 中设置
216+
> 虽然不推荐,但如果确实需要关闭某些安全功能,可以在 `config/config.default.js` 中设置以下代码:
225217
226-
```
218+
```javascript
227219
exports.security = {
228220
csrf: false
229221
};
@@ -303,7 +295,7 @@ exports.index = async (ctx) => {
303295
### 中间件的使用
304296

305297
如果我们想把用户某一类请求的参数都大写,可以通过中间件来实现。
306-
这里我们只是简单说明下如何使用中间件,更多请查看 [中间件](./middleware.md)
298+
这里我们仅简单说明如何使用中间件,更多信息请参考[中间件](./middleware.md)
307299

308300
```js
309301
// app/controller/search.js
@@ -325,7 +317,7 @@ module.exports = (app) => {
325317
's',
326318
'/search',
327319
app.middleware.uppercase(),
328-
app.controller.search,
320+
app.controller.search.index,
329321
);
330322
};
331323

@@ -334,9 +326,9 @@ module.exports = (app) => {
334326

335327
### 太多路由映射?
336328

337-
如上所述,我们并不建议把路由规则逻辑散落在多个地方,会给排查问题带来困扰
329+
如上所述,我们不建议在多个地方分散路由规则,这可能会导致问题排查困难
338330

339-
若确实有需求,可以如下拆分
331+
如果确实存在需求,可以采用如下方法拆分
340332

341333
```js
342334
// app/router.js
@@ -358,4 +350,4 @@ module.exports = (app) => {
358350
};
359351
```
360352

361-
也可直接使用 [egg-router-plus](https://github.com/eggjs/egg-router-plus)
353+
如果需要更好的路由组织方式,也可以直接使用 [egg-router-plus](https://github.com/eggjs/egg-router-plus)

‎site/docs/basics/schedule.zh-CN.md

+32-34
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,15 @@ order: 10
66
虽然我们通过框架开发的 HTTP Server 是请求响应模型的,但是仍然还会有许多场景需要执行一些定时任务,例如:
77

88
1. 定时上报应用状态。
9-
1. 定时从远程接口更新本地缓存。
10-
1. 定时进行文件切割、临时文件删除。
9+
2. 定时从远程接口更新本地缓存。
10+
3. 定时进行文件切割、临时文件删除。
1111

1212
框架提供了一套机制来让定时任务的编写和维护更加优雅。
13-
1413
## 编写定时任务
1514

1615
所有的定时任务都统一存放在 `app/schedule` 目录下,每一个文件都是一个独立的定时任务,可以配置定时任务的属性和要执行的方法。
1716

18-
一个简单的例子,我们定义一个更新远程数据到内存缓存的定时任务,就可以在 `app/schedule` 目录下创建一个 `update_cache.js` 文件
17+
一个简单的例子,我们定义一个更新远程数据到内存缓存的定时任务,就可以在 `app/schedule` 目录下创建一个 `update_cache.js` 文件
1918

2019
```js
2120
const Subscription = require('egg').Subscription;
@@ -41,7 +40,7 @@ class UpdateCache extends Subscription {
4140
module.exports = UpdateCache;
4241
```
4342

44-
还可以简写为
43+
还可以简写为
4544

4645
```js
4746
module.exports = {
@@ -71,7 +70,7 @@ module.exports = {
7170

7271
#### interval
7372

74-
通过 `schedule.interval` 参数来配置定时任务的执行时机,定时任务将会每间隔指定的时间执行一次。interval 可以配置成
73+
通过 `schedule.interval` 参数来配置定时任务的执行时机,定时任务将会每间隔指定的时间执行一次。interval 可以配置成
7574

7675
- 数字类型,单位为毫秒数,例如 `5000`
7776
- 字符类型,会通过 [ms](https://github.com/zeit/ms) 转换成毫秒数,例如 `5s`
@@ -92,15 +91,15 @@ module.exports = {
9291
**注意:cron-parser 支持可选的秒(linux crontab 不支持)。**
9392

9493
```bash
95-
* * * * * *
96-
┬ ┬ ┬ ┬
97-
│ │ │ │ |
98-
│ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun)
99-
│ │ │ └───── month (1 - 12)
100-
│ │ └────────── day of month (1 - 31)
101-
└─────────────── hour (0 - 23)
102-
└──────────────────── minute (0 - 59)
103-
└───────────────────────── second (0 - 59, optional)
94+
* * * * * *
95+
┬ ┬ ┬ ┬
96+
│ │ │ │ │
97+
│ │ │ │ └─ 周日(0 - 7)(0 或 7 是周日)
98+
│ │ │ └─── 月份(1 - 12
99+
│ │ └───── 日期(1 - 31
100+
└─────── 小时(0 - 23
101+
│ └───────── 分钟(0 - 59
102+
└─────────── 秒(0 - 59,可选)
104103
```
105104

106105
```js
@@ -121,10 +120,10 @@ module.exports = {
121120

122121
### 其他参数
123122

124-
除了刚才介绍到的几个参数之外,定时任务还支持这些参数
123+
除了上述介绍的几个参数,定时任务还支持以下参数
125124

126-
- `cronOptions`: 配置 cron 的时区等,参见 [cron-parser](https://github.com/harrisiirak/cron-parser#options) 文档
127-
- `immediate`配置了该参数为 true 时,这个定时任务会在应用启动并 ready 后立刻执行一次这个定时任务
125+
- `cronOptions`配置 cron 的时区等,参见 [cron-parser](https://github.com/harrisiirak/cron-parser#options) 文档
126+
- `immediate`配置该参数为 true 时,这个定时任务会在应用启动并 ready 后立即执行一次这个定时任务
128127
- `disable`:配置该参数为 true 时,这个定时任务不会被启动。
129128
- `env`:数组,仅在指定的环境下才启动该定时任务。
130129

@@ -141,10 +140,9 @@ config.customLogger = {
141140
},
142141
};
143142
```
144-
145143
### 动态配置定时任务
146144

147-
有时候我们需要配置定时任务的参数。定时任务还有支持另一种写法
145+
有时候,我们需要配置定时任务的参数。定时任务还可以支持另一种写法
148146

149147
```js
150148
module.exports = (app) => {
@@ -165,11 +163,11 @@ module.exports = (app) => {
165163

166164
## 手动执行定时任务
167165

168-
我们可以通过 `app.runSchedule(schedulePath)` 来运行一个定时任务。`app.runSchedule` 接受一个定时任务文件路径(`app/schedule` 目录下的相对路径或者完整的绝对路径),执行对应的定时任务,返回一个 Promise。
166+
我们可以通过 `app.runSchedule(schedulePath)` 来运行一个定时任务。`app.runSchedule` 接受一个定时任务文件路径(位于 `app/schedule` 目录下的相对路径或者完整的绝对路径),执行对应的定时任务,并返回一个 Promise 对象
169167

170-
有一些场景我们可能需要手动的执行定时任务,例如
168+
在以下场景中,我们可能需要手动执行定时任务:
171169

172-
- 通过手动执行定时任务可以更优雅的编写对定时任务的单元测试
170+
- 手动执行定时任务可以更优雅地编写定时任务的单元测试
173171

174172
```js
175173
const mm = require('egg-mock');
@@ -183,12 +181,12 @@ it('should schedule work fine', async () => {
183181
});
184182
```
185183

186-
- 应用启动时,手动执行定时任务进行系统初始化,等初始化完毕后再启动应用。参见[应用启动自定义](./app-start.md)章节我们可以在 `app.js` 中编写初始化逻辑。
184+
- 应用启动时,可以手动执行定时任务进行系统初始化。在初始化完毕后,再启动应用。具体可以参见[应用启动自定义](./app-start.md)章节我们可以在 `app.js` 中编写初始化逻辑。
187185

188186
```js
189187
module.exports = (app) => {
190188
app.beforeStart(async () => {
191-
// 保证应用启动监听端口前数据已经准备好了
189+
// 保证应用启动监听端口前,数据已经准备好
192190
// 后续数据的更新由定时任务自动触发
193191
await app.runSchedule('update_cache');
194192
});
@@ -197,27 +195,27 @@ module.exports = (app) => {
197195

198196
## 扩展定时任务类型
199197

200-
默认框架提供的定时任务只支持每台机器的单个进程执行和全部进程执行,有些情况下,我们的服务并不是单机部署的,这时候可能有一个集群的某一个进程执行一个定时任务的需求
198+
虽然默认的框架提供的定时任务只支持单个进程执行和全部进程执行,但是在某些情况下,比如服务非单机部署时,我们可能需要集群中的某一个进程执行定时任务
201199

202-
框架并没有直接提供此功能,但开发者可以在上层框架自行扩展新的定时任务类型
200+
虽然框架没有直接提供此功能,开发者可在上层框架中自行扩展新的定时任务类型
203201

204-
`agent.js` 中继承 `agent.ScheduleStrategy`,然后通过 `agent.schedule.use()` 注册即可
202+
`agent.js` 中,继承 `agent.ScheduleStrategy`,然后通过 `agent.schedule.use()` 方法注册即可
205203

206204
```js
207205
module.exports = (agent) => {
208206
class ClusterStrategy extends agent.ScheduleStrategy {
209207
start() {
210-
// 订阅其他的分布式调度服务发送的消息,收到消息后让一个进程执行定时任务
211-
// 用户在定时任务的 schedule 配置中来配置分布式调度的场景(scene)
208+
// 订阅其他分布式调度服务发送的消息,收到消息后让一个进程执行定时任务
209+
// 用户可以在定时任务的 schedule 属性中配置分布式调度的场景(scene)
212210
agent.mq.subscribe(this.schedule.scene, () => this.sendOne());
213211
}
214212
}
215213
agent.schedule.use('cluster', ClusterStrategy);
216214
};
217215
```
218216

219-
`ScheduleStrategy` 基类提供了
217+
`ScheduleStrategy` 基类提供了以下方法
220218

221-
- `this.schedule` - 定时任务的属性,`disable` 是默认统一支持的,其他配置可以自行解析
222-
- `this.sendOne(...args)` - 随机通知一个 worker 执行 task,`args` 会传递给 `subscribe(...args)``task(ctx, ...args)`
223-
- `this.sendAll(...args)` - 通知所有的 worker 执行 task。
219+
- `this.schedule` - 定时任务的属性,所有任务默认支持的 `disable` 属性,以及其他自定义配置的解析
220+
- `this.sendOne(...args)` - 随机通知某个 worker 执行 task,`args` 会传递给 `subscribe(...args)``task(ctx, ...args)` 方法
221+
- `this.sendAll(...args)` - 通知所有的 worker 执行 task。

‎site/docs/basics/service.zh-CN.md

+35-40
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,15 @@ title: 服务(Service)
33
order: 8
44
---
55

6-
简单来说,Service 就是在复杂业务场景下用于做业务逻辑封装的一个抽象层,提供这个抽象有以下几个好处:
7-
8-
- 保持 Controller 中的逻辑更加简洁。
9-
- 保持业务逻辑的独立性,抽象出来的 Service 可以被多个 Controller 重复调用。
10-
- 将逻辑和展现分离,更容易编写测试用例,测试用例的编写具体可以查看[这里](../core/unittest.md)
6+
简单来说,Service 就是在复杂业务场景下用于做业务逻辑封装的一个抽象层,它的提供具有以下几个优点:
117

8+
- 保持 Controller 中的逻辑更简洁。
9+
- 保持业务逻辑的独立性,抽象出的 Service 可以被多个 Controller 重复使用。
10+
- 分离逻辑和展示,这样更便于编写测试用例。具体的测试用例编写方法,可以参见[这里](../core/unittest.md)
1211
## 使用场景
1312

14-
- 复杂数据的处理,比如要展现的信息需要从数据库获取,还要经过一定的规则计算,才能返回用户显示。或者计算完成后,更新到数据库。
15-
- 第三方服务的调用,比如 GitHub 信息获取等。
16-
13+
- 数据处理:当需要展示的信息须从数据库获取,并经规则计算后才能显示给用户,或计算后需更新数据库时。
14+
- 第三方服务调用:例如获取 GitHub 信息等。
1715
## 定义 Service
1816

1917
```js
@@ -24,7 +22,7 @@ class UserService extends Service {
2422
async find(uid) {
2523
const user = await this.ctx.db.query(
2624
'select * from user where uid = ?',
27-
uid,
25+
uid
2826
);
2927
return user;
3028
}
@@ -35,44 +33,41 @@ module.exports = UserService;
3533

3634
### 属性
3735

38-
每一次用户请求,框架都会实例化对应的 Service 实例,由于它继承于 `egg.Service`故拥有下列属性方便我们进行开发
36+
每一次用户请求,框架都会实例化对应的 Service 实例。因为它继承自 `egg.Service`所以我们拥有以下属性便于开发
3937

40-
- `this.ctx`: 当前请求的上下文 [Context](./extend.md#context) 对象的实例,通过它我们可以拿到框架封装好的处理当前请求的各种便捷属性和方法
41-
- `this.app`: 当前应用 [Application](./extend.md#application) 对象的实例,通过它我们可以拿到框架提供的全局对象和方法
42-
- `this.service`:应用定义的 [Service](./service.md),通过它我们可以访问到其他业务层,等价于 `this.ctx.service`
43-
- `this.config`:应用运行时的[配置项](./config.md)
44-
- `this.logger`:logger 对象,上面有四个方法`debug``info``warn``error`),分别代表打印四个不同级别的日志,使用方法和效果与 [context logger](../core/logger.md#context-logger) 中介绍的一样,但是通过这个 logger 对象记录的日志,在日志前面会加上打印该日志的文件路径,以便快速定位日志打印位置
38+
- `this.ctx`当前请求的上下文 [Context](./extend.md#context) 对象实例。通过它,我们可以获取框架封装的处理当前请求的各种便捷属性和方法
39+
- `this.app`当前应用 [Application](./extend.md#application) 对象实例。通过它,我们可以访问框架提供的全局对象和方法
40+
- `this.service`:应用定义的 [Service](./service.md)。通过它,我们可以访问到其他业务层,等同于 `this.ctx.service`
41+
- `this.config`:应用运行时的 [配置项](./config.md)
42+
- `this.logger`:logger 对象。它有四个方法`debug``info``warn``error`),分别代表不同级别的日志。使用方法和效果与 [context logger](../core/logger.md#context-logger) 所述一致。但通过这个 logger 记录的日志,在日志前会加上文件路径,方便定位日志位置
4543

4644
### Service ctx 详解
4745

48-
为了可以获取用户请求的链路,我们在 Service 初始化中,注入了请求上下文, 用户在方法中可以直接通过 `this.ctx` 来获取上下文相关信息。关于上下文的具体详解可以参看 [Context](./extend.md#context),
49-
有了 ctx 我们可以拿到框架给我们封装的各种便捷属性和方法。比如我们可以用:
46+
为了能获取用户请求的链路,在 Service 初始化时,注入了请求上下文。用户可以通过 `this.ctx` 直接获取上下文相关信息。关于上下文的更多详细解释,请参考 [Context](./extend.md#context)。有了 `ctx`,我们可以:
5047

51-
- `this.ctx.curl` 发起网络调用。
52-
- `this.ctx.service.otherService` 调用其他 Service。
53-
- `this.ctx.db` 发起数据库调用等, db 可能是其他插件提前挂载到 app 上的模块。
48+
- 使用 `this.ctx.curl` 发起网络调用。
49+
- 通过 `this.ctx.service.otherService` 调用其他 Service。
50+
- 调用 `this.ctx.db` 发起数据库操作,`db` 可能是插件预挂载到 app 上的模块。
5451

5552
### 注意事项
5653

57-
- Service 文件必须放在 `app/service` 目录,可以支持多级目录,访问的时候可以通过目录名级联访问
54+
- Service 文件必须放在 `app/service` 目录下,支持多级目录。可以通过目录名级联访问
5855

5956
```js
57+
// app/service/biz/user.js 对应到 ctx.service.biz.user
6058
app/service/biz/user.js => ctx.service.biz.user
59+
// app/service/sync_user.js 对应到 ctx.service.syncUser
6160
app/service/sync_user.js => ctx.service.syncUser
61+
// app/service/HackerNews.js 对应到 ctx.service.hackerNews
6262
app/service/HackerNews.js => ctx.service.hackerNews
6363
```
6464

65-
- 一个 Service 文件只能包含一个类, 这个类需要通过 `module.exports` 的方式返回。
66-
- Service 需要通过 Class 的方式定义,父类必须是 `egg.Service`
67-
- Service 不是单例,是 **请求级别** 的对象,框架在每次请求中首次访问 `ctx.service.xx` 时延迟实例化,所以 Service 中可以通过 this.ctx 获取到当前请求的上下文。
68-
69-
## 使用 Service
70-
71-
下面就通过一个完整的例子,看看怎么使用 Service。
72-
65+
- 一个 Service 文件仅包含一个类,该类需通过 `module.exports` 导出。
66+
- Service 应通过 Class 形式定义,且继承自 `egg.Service`
67+
- Service 不是单例,它是请求级别的对象。框架在每次请求中初次访问 `ctx.service.xx` 时才进行实例化。因此,Service 中可以通过 `this.ctx` 获取当前请求的上下文。
7368
```js
7469
// app/router.js
75-
module.exports = (app) => {
70+
module.exports = app => {
7671
app.router.get('/user/:id', app.controller.user.info);
7772
};
7873

@@ -92,31 +87,31 @@ module.exports = UserController;
9287
const Service = require('egg').Service;
9388
class UserService extends Service {
9489
// 默认不需要提供构造函数。
95-
// constructor(ctx) {
96-
// super(ctx); 如果需要在构造函数做一些处理,一定要有这句话,才能保证后面 `this.ctx`的使用。
97-
// // 就可以直接通过 this.ctx 获取 ctx 了
98-
// // 还可以直接通过 this.app 获取 app 了
99-
// }
90+
/* constructor(ctx) {
91+
super(ctx); // 如果需要在构造函数做一些处理,一定要有这句话,才能保证后面 `this.ctx` 的使用。
92+
// 就可以直接通过 this.ctx 获取 ctx 了
93+
// 还可以直接通过 this.app 获取 app 了
94+
} */
10095
async find(uid) {
101-
// 假如 我们拿到用户 id 从数据库获取用户详细信息
96+
// 假如我们拿到用户 id,从数据库获取用户详细信息
10297
const user = await this.ctx.db.query(
10398
'select * from user where uid = ?',
104-
uid,
99+
uid
105100
);
106101

107-
// 假定这里还有一些复杂的计算,然后返回需要的信息
102+
// 假定这里还有一些复杂的计算,然后返回需要的信息
108103
const picture = await this.getPicture(uid);
109104

110105
return {
111106
name: user.user_name,
112107
age: user.age,
113-
picture,
108+
picture
114109
};
115110
}
116111

117112
async getPicture(uid) {
118113
const result = await this.ctx.curl(`http://photoserver/uid=${uid}`, {
119-
dataType: 'json',
114+
dataType: 'json'
120115
});
121116
return result.data;
122117
}

‎site/docs/basics/structure.zh-CN.md

+36-35
Original file line numberDiff line numberDiff line change
@@ -8,36 +8,36 @@ order: 1
88
```bash
99
egg-project
1010
├── package.json
11-
├── app.js (可选)
12-
├── agent.js (可选)
11+
├── app.js(可选)
12+
├── agent.js(可选)
1313
├── app
1414
| ├── router.js
1515
│ ├── controller
16-
| └── home.js
17-
│ ├── service (可选)
18-
| └── user.js
19-
│ ├── middleware (可选)
20-
| └── response_time.js
21-
│ ├── schedule (可选)
22-
| └── my_task.js
23-
│ ├── public (可选)
24-
| └── reset.css
25-
│ ├── view (可选)
26-
| └── home.tpl
27-
│ └── extend (可选)
28-
│ ├── helper.js (可选)
29-
│ ├── request.js (可选)
30-
│ ├── response.js (可选)
31-
│ ├── context.js (可选)
32-
│ ├── application.js (可选)
33-
│ └── agent.js (可选)
16+
└── home.js
17+
│ ├── service(可选)
18+
└── user.js
19+
│ ├── middleware(可选)
20+
└── response_time.js
21+
│ ├── schedule(可选)
22+
└── my_task.js
23+
│ ├── public(可选)
24+
└── reset.css
25+
│ ├── view(可选)
26+
└── home.tpl
27+
│ └── extend(可选)
28+
│ ├── helper.js(可选)
29+
│ ├── request.js(可选)
30+
│ ├── response.js(可选)
31+
│ ├── context.js(可选)
32+
│ ├── application.js(可选)
33+
│ └── agent.js(可选)
3434
├── config
3535
| ├── plugin.js
3636
| ├── config.default.js
3737
│ ├── config.prod.js
38-
| ├── config.test.js (可选)
39-
| ├── config.local.js (可选)
40-
| └── config.unittest.js (可选)
38+
| ├── config.test.js(可选)
39+
| ├── config.local.js(可选)
40+
| └── config.unittest.js(可选)
4141
└── test
4242
├── middleware
4343
| └── response_time.test.js
@@ -49,21 +49,22 @@ egg-project
4949

5050
- `app/router.js` 用于配置 URL 路由规则,具体参见 [Router](./router.md)
5151
- `app/controller/**` 用于解析用户的输入,处理后返回相应的结果,具体参见 [Controller](./controller.md)
52-
- `app/service/**` 用于编写业务逻辑层,可选,建议使用,具体参见 [Service](./service.md)
53-
- `app/middleware/**` 用于编写中间件,可选,具体参见 [Middleware](./middleware.md)
54-
- `app/public/**` 用于放置静态资源,可选,具体参见内置插件 [egg-static](https://github.com/eggjs/egg-static)
55-
- `app/extend/**` 用于框架的扩展,可选,具体参见[框架扩展](./extend.md)
56-
- `config/config.{env}.js` 用于编写配置文件,具体参见[配置](./config.md)
57-
- `config/plugin.js` 用于配置需要加载的插件,具体参见[插件](./plugin.md)
58-
- `test/**` 用于单元测试,具体参见[单元测试](../core/unittest.md)
59-
- `app.js``agent.js` 用于自定义启动时的初始化工作,可选,具体参见[启动自定义](./app-start.md)。关于`agent.js`的作用参见[Agent 机制](../core/cluster-and-ipc.md#agent-机制)
52+
- `app/service/**` 用于编写业务逻辑层,建议使用,具体参见 [Service](./service.md)
53+
- `app/middleware/**` 用于编写中间件,具体参见 [Middleware](./middleware.md)
54+
- `app/public/**` 用于放置静态资源,具体参见内置插件 [egg-static](https://github.com/eggjs/egg-static)
55+
- `app/extend/**` 用于框架的扩展,具体参见 [框架扩展](./extend.md)
56+
- `config/config.{env}.js` 用于编写配置文件,具体参见 [配置](./config.md)
57+
- `config/plugin.js` 用于配置需要加载的插件,具体参见 [插件](./plugin.md)
58+
- `test/**` 用于单元测试,具体参见 [单元测试](../core/unittest.md)
59+
- `app.js``agent.js` 用于自定义启动时的初始化工作,具体参见 [启动自定义](./app-start.md)。关于 `agent.js` 的作用,参见 [Agent 机制](../core/cluster-and-ipc.md#agent-机制)
60+
6061

6162
由内置插件约定的目录:
6263

63-
- `app/public/**` 用于放置静态资源,可选,具体参见内置插件 [egg-static](https://github.com/eggjs/egg-static)
64-
- `app/schedule/**` 用于定时任务,可选,具体参见[定时任务](./schedule.md)
64+
- `app/public/**` 用于放置静态资源,具体参见内置插件 [egg-static](https://github.com/eggjs/egg-static)
65+
- `app/schedule/**` 用于定时任务,具体参见 [定时任务](./schedule.md)
6566

6667
**若需自定义自己的目录规范,参见 [Loader API](https://eggjs.org/zh-cn/advanced/loader.html)**
6768

68-
- `app/view/**` 用于放置模板文件,可选,由模板插件约定,具体参见[模板渲染](../core/view.md)
69-
- `app/model/**` 用于放置领域模型,可选,由领域类相关插件约定,[egg-sequelize](https://github.com/eggjs/egg-sequelize)
69+
- `app/view/**` 用于放置模板文件,具体参见 [模板渲染](../core/view.md)
70+
- `app/model/**` 用于放置领域模型,如 [`egg-sequelize`](https://github.com/eggjs/egg-sequelize) 等领域类相关插件

0 commit comments

Comments
 (0)
Please sign in to comment.