Egg基础与思路
Egg.js基础 与 使用思路
# Egg.js入门
# 搭建环境、熟悉结构
# 使用脚手架
npm init egg
2
项目目录结构的核心包含
package.json
app // 项目代码
- router // 路由
- controller // 控制层
- service // 业务逻辑层
- view // 模版
- public // 静态资源
- middleware // 中间件
config // 全局配置
-
test // 单元测试
2
3
4
5
6
7
8
9
10
11
一般来说,从浏览器访问路由开始,框架会按照以下步骤开始处理:
- router,用来根据被访问的地址匹配到正确的控制层controller
- controller,函数根据数据和模版来返回render后的结果
根据实际业务,controller层可能从数据库 / 服务端获取数据,然后根据数据 / 业务逻辑与模版拼装成html或者某种类型的数据
# router
module.exports = app => {
const { router, controller } = app;
router.get('/index', controller.index.home); // 支持字符串匹配
router.post(/\/api\/([\w-.\/]+)/, controller.forward.api); // 支持正则匹配
router.get('/user/:id', controller.user.order); // 可以传递参数
require('./router/admin')(app); // 支持文件映射,如果路由太多的情况
const gzip = app.middleware.gzip({ threshold: 1024 });
router.get('/detail-zip', gzip, controller.detail.item); // 支持自定义中间件
}
2
3
4
5
6
7
8
9
10
11
router对象包含了get、post、put、delete、optopns等,这是根据浏览器的请求类型来的,另外router还支持redirect函数,用来重定向
这些方法的参数一样,第一个是路由匹配规则,支持字符串、正则等形式,第二个是触发的controller层函数
# controller
controller返回的数据类型很丰富,下面的例子是返回json。如果有什么问题,需要随用随查。
const Controller = require('egg').Controller;
class PostController extends Controller {
async create() {
const { ctx, service } = this;
const req = Object.assign(ctx.request.body, { time: new Date().getTime() });
// 调用 Service 进行业务处理
const res = await service.post.create(req);
// json
// 设置响应内容和响应状态码
ctx.body = { id: res.id };
ctx.status = 201;
// html
// await ctx.render('home.tpl', { name: 'egg' });
}
}
module.exports = PostController;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
controller层拼装的是最后返回的数据(不仅仅是html / json),拼凑数据的方法可以是自定义数据 / sql查询数据 / 服务端查询数据 / 文件解析数据 等,最后返回的结果也是多种多样,所以需要注意的是:header中的属性,返回数据类型,cookie等,如果原来对HTTP不是那么熟悉,或者对HTTP响应不是很熟悉的,在实际使用过程中可能会遇到很多麻烦。
# middleware
在 router 部分,有涉及到 middleware(中间件),它的具体功能是在路由匹配与执行controller之间,增加一步公共方法可以格式化数据或者其他功能
// 定义一个中间件
// app/middleware/gzip.js
const isJSON = require('koa-is-json'); // 校验插件
const zlib = require('zlib'); // 压缩插件
async function gzip(ctx, next) {
await next(); // 这一步代表:执行controller的过程,所以根据业务逻辑可以把这一步放在正确位置上
// 后续中间件执行完成后将响应体转换成 gzip
let body = ctx.body;
if (!body) return;
if (isJSON(body)) body = JSON.stringify(body);
// 设置 gzip body,修正响应头
const stream = zlib.createGzip();
stream.end(body); // 压缩
ctx.body = stream;
ctx.set('Content-Encoding', 'gzip'); // header设置
}
// 使用中间件
// 全局模式
// config.default.js
module.exports = {
// 配置需要的中间件,数组顺序即为中间件的加载顺序
middleware: ['gzip'],
};
// 局部模式
// router中使用
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# service
service是处理业务逻辑的部分,返回具体数据
const Service = require('egg').Service;
class UserService extends Service {
async find(uid) {
const user = await this.ctx.db.query(
'select * from user where uid = ?',
uid,
); // egg直连数据库获取
// 还可以发送请求获取
return user;
}
}
module.exports = UserService;
2
3
4
5
6
7
8
9
10
11
12
# view
egg可以使用多种模版引擎,只需引入插件(包名:egg-view-XX)即可
// config.default.js
config.view = {
root: [ // 自定义页面资源地址,可以配置多个
path.join(appInfo.baseDir, 'app/view'), // 默认值
// path.join(appInfo.baseDir, 'path/to/another'),
].join(','),
cache: true, // 默认值, 缓存文件路径
// defaultViewEngine: 'ejs', // 默认模板引擎 去掉 不需要编译html文件
defaultExtension: '.ejs', // 给render第一个参数自带文件后缀
mapping: { // 根据文件后缀匹配模板引擎
'.ejs': 'ejs',
'.html': '',
},
};
2
3
4
5
6
7
8
9
10
11
12
13
14
# i18n
国际化的取值优先级从高到低依次是:
- query: /?locale=en-US
- cookie: locale=zh-TW
- header: Accept-Language: zh-CN,zh;q=0.5
// config/locale/en.json
{
"view": {
"home": {
"title": "title value" // json格式返回具体数据
},
}
}
// config.default.js
config.i18n = {
defaultLocale: 'en',
};
// view
__('view.home.title') // 取值函数
// controller
ctx.__('view.home.title') // __函数挂载在ctx下
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// config/locale/en.json
{
"view": {
"home": {
"title": "title value" // json格式返回具体数据
},
}
}
// config.default.js
config.i18n = {
defaultLocale: 'en',
};
// view
__('view.home.title') // 取值函数
// controller
ctx.__('view.home.title') // __函数挂载在ctx下
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# helper
与i18n类似,本质上是一个工具函数,可以便捷的在view中处理数据
// app/extend/helper.js
// 打印日志
const log = (data, name) => {
return `<script>console.log(${_default(data)}, "${name || ''}")</script>`
}
module.exports = {
log
}
// 使用方法,类似__函数
// view
helper.log(formError)
2
3
4
5
6
7
8
9
10
11
# 总结
学会Egg.js只需要搞清楚:Egg的各个部分的功能,捋清楚HTTP的流程,就可以使用了。
如果在使用的过程中遇到了什么难点,还有很多插件可以支持,是在不行了,就用node的原生api处理也是没问题的。