node.js——阿里企业级服务框架Egg搭建
egg是阿里开源的企业级框架,主要设计理念为平衡团队之间的技术差异,专注于提供 Web 开发的核心功能和一套灵活可扩展的插件机制。通过 Egg,团队的架构师和技术负责人可以非常容易地基于自身的技术架构在 Egg 基础上扩展出适合自身业务场景的框架。
Egg 的插件机制有很高的可扩展性,一个插件只做一件事(比如 Nunjucks 模板封装成了 egg-view-nunjucks、MySQL 数据库封装成了 egg-mysql)。Egg 通过框架聚合这些插件,并根据自己的业务场景定制配置,这样应用的开发成本就变得很低。
Egg 奉行『约定优于配置』,按照一套统一的约定进行应用开发,团队内部采用这种方式可以减少开发人员的学习成本,开发人员不再是『钉子』,可以流动起来。没有约定的团队,沟通成本是非常高的,比如有人会按目录分栈而其他人按目录分功能,开发者认知不一致很容易犯错。但约定不等于扩展性差,相反 Egg 有很高的扩展性,可以按照团队的约定定制框架。使用 Loader 可以让框架根据不同环境定义默认配置,还可以覆盖 Egg 的默认约定。
官方文档 https://eggjs.org/zh-cn/intro/quickstart.html
主要模块:
一、路由(Router)
app/router.js 里面定义 URL 路由规则
// app/router.js
module.exports = app => {const { router, controller } = app;router.get('/user/:id', controller.user.info);
};
app/controller 目录下面实现 Controller
// app/controller/user.js
class UserController extends Controller {async info() {const { ctx } = this;ctx.body = {name: `hello ${ctx.params.id}`,};}
}
在 Router 定义中, 可以支持多个 Middleware 串联执行
Controller 必须定义在 app/controller 目录中。
一个文件里面也可以包含多个 Controller 定义,在定义路由的时候,可以通过 ${fileName}.${functionName} 的方式指定对应的 Controller。
Controller 支持子目录,在定义路由的时候,可以通过 ${directoryName}.${fileName}.${functionName} 的方式制定对应的 Controller。
路由定义方式:
// app/router.js
module.exports = app => {const { router, controller } = app;router.get('/home', controller.home);router.get('/user/:id', controller.user.page);router.post('/admin', isAdmin, controller.admin);router.post('/user', isLoginUser, hasAdminPermission, controller.user.create);router.post('/api/v1/comments', controller.v1.comments.create); // app/controller/v1/comments.js
};
二、控制器(Controller)
Controller 负责解析用户的输入,处理后返回相应的结果,例如
在 RESTful 接口中,Controller 接受用户的参数,从数据库中查找内容返回给用户或者将用户的请求更新到数据库中。
在 HTML 页面请求中,Controller 根据用户访问不同的 URL,渲染不同的模板得到 HTML 返回给用户。
在代理服务器中,Controller 将用户的请求转发到其他服务器上,并将其他服务器的处理结果返回给用户。
框架推荐 Controller 层主要对用户的请求参数进行处理(校验、转换),然后调用对应的 service 方法处理业务,得到业务结果后封装并返回:
获取用户通过 HTTP 传递过来的请求参数。
校验、组装参数。
调用 Service 进行业务处理,必要时处理转换 Service 的返回结果,让它适应用户的需求。
通过 HTTP 将结果响应给用户。
参数获取:
Query String 方式
// app/router.js
module.exports = app => {app.router.get('/search', app.controller.search.index);
};// app/controller/search.js
exports.index = async ctx => {ctx.body = `search: ${ctx.query.name}`;
};
参数命名方式
// app/router.js
module.exports = app => {app.router.get('/user/:id/:name', app.controller.user.info);
};// app/controller/user.js
exports.info = async ctx => {ctx.body = `user: ${ctx.params.id}, ${ctx.params.name}`;
};
返回数据:
ctx.response.body(简写为ctx.body),不建议使用简写语法,因为会造成跟ctx.request.body的混淆误解。作为企业级应用开发,要考虑到新人接手的可读性和学习效率。
重定向:
框架通过 security 插件覆盖了 koa 原生的 ctx.redirect 实现,以提供更加安全的重定向。
ctx.redirect(url) 如果不在配置的白名单域名内,则禁止跳转。
ctx.unsafeRedirect(url) 不判断域名,直接跳转,一般不建议使用,明确了解可能带来的风险后使用。
用户如果使用ctx.redirect方法,需要在应用的配置文件中做如下配置:
// config/config.default.js
exports.security = {domainWhiteList:['.domain.com'], // 安全白名单,以 . 开头
};
若用户没有配置 domainWhiteList 或者 domainWhiteList数组内为空,则默认会对所有跳转请求放行,即等同于ctx.unsafeRedirect(url)
三、服务(Service)
Service 就是在复杂业务场景下用于做业务逻辑封装的一个抽象层,提供这个抽象有以下几个好处:
保持 Controller 中的逻辑更加简洁。
保持业务逻辑的独立性,抽象出来的 Service 可以被多个 Controller 重复调用。
将逻辑和展现分离,更容易编写测试用例,测试用例的编写具体可以查看这里。
定义 Service
// app/service/user.js
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);return user;}
}module.exports = UserService;
Service ctx 详解
为了可以获取用户请求的链路,我们在 Service 初始化中,注入了请求上下文, 用户在方法中可以直接通过 this.ctx 来获取上下文相关信息。关于上下文的具体详解可以参看 Context, 有了 ctx 我们可以拿到框架给我们封装的各种便捷属性和方法。比如我们可以用:
this.ctx.curl 发起网络调用。
this.ctx.service.otherService 调用其他 Service。
this.ctx.db 发起数据库调用等, db 可能是其他插件提前挂载到 app 上的模块。
// app/router.js
module.exports = app => {app.router.get('/user/:id', app.controller.user.info);
};// app/controller/user.js
const Controller = require('egg').Controller;
class UserController extends Controller {async info() {const { ctx } = this;const userId = ctx.params.id;const userInfo = await ctx.service.user.find(userId);ctx.body = userInfo;}
}
module.exports = UserController;// app/service/user.js
const Service = require('egg').Service;
class UserService extends Service {// 默认不需要提供构造函数。// constructor(ctx) {// super(ctx); 如果需要在构造函数做一些处理,一定要有这句话,才能保证后面 `this.ctx`的使用。// // 就可以直接通过 this.ctx 获取 ctx 了// // 还可以直接通过 this.app 获取 app 了// }async find(uid) {// 假如 我们拿到用户 id 从数据库获取用户详细信息const user = await this.ctx.db.query('select * from user where uid = ?', uid);// 假定这里还有一些复杂的计算,然后返回需要的信息。const picture = await this.getPicture(uid);return {name: user.user_name,age: user.age,picture,};}async getPicture(uid) {const result = await this.ctx.curl(`http://photoserver/uid=${uid}`, { dataType: 'json' });return result.data;}
}
module.exports = UserService;
常见问题:
启动服务:
npm run dev
PM2 启动:
egg不推荐使用 PM2 启动,但仍然可以使用。
在项目根目录定义启动文件:
// server.js
const egg = require('egg');const workers = Number(process.argv[2] || require('os').cpus().length);
egg.startCluster({workers,baseDir: __dirname,
});
pm2 start server.js
修改端口:
/config/config.default.js
config.cluster = {listen: {path: '',port: 7002,hostname: '0.0.0.0',},};
csrf 报错:
Egg 内置的 egg-security 插件默认对所有『非安全』的方法,例如 POST,PUT,DELETE 都进行 CSRF 校验。
请求遇到 csrf 报错通常是因为没有加正确的 csrf token 导致,如不需要csrf防范,在/config/config.default.js里设置:
config.security = {csrf: {enable: false,},};
如需csrf校验,阅读 安全威胁 CSRF 的防范
开发示例:
//app/router.js
'use strict';
module.exports = app => {const { router, controller } = app;router.get('/', controller.home.index);router.get('/Title1', controller.test.Title1);router.post('/Title2', controller.test.Title2);
};
//app/controller/test.js
'use strict';
const Controller = require('egg').Controller;
class TestController extends Controller {async Title1() {const query = this.ctx.query;const adds = query.l1 + ' ' + query.l2;const dataList = {list: [{ id: 1, title: 'this is news 1', url: '/news/1', l1: query.l1, sum: adds },{ id: 2, title: 'this is news 2', url: '/news/2', l2: query.l2, sum: adds }],};this.ctx.response.body = dataList;}async Title2() {const adds = this.ctx.request.body.l1 + this.ctx.request.body.l2;const dataList = {list: [{ id: 1, title: 'this is news 1', url: '/news/1', sum: adds },{ id: 2, title: 'this is news 2', url: '/news/2', sum: adds }],};this.ctx.response.body = dataList;}
}
module.exports = TestController;
node.js——阿里企业级服务框架Egg搭建相关推荐
- Pomelo:网易开源基于 Node.js 的游戏服务端框架
Pomelo 是基于 Node.js 的高性能.分布式游戏服务器框架.它包括基础的开发框架和相关的扩展组件(库和工具包),可以帮助你省去游戏开发枯燥中的重复劳动和底层逻辑的开发.Pomelo 不但适用 ...
- node.js安装express(零起点搭建本地测试服务器)- 教程篇
(含图文教程.代码对比,等)node.js安装express(零起点搭建本地测试服务器)- 教程篇 原教程 · 参考地址 执行step3之后,结果截图 · 如下图2 : 之后,执行step4,截图如下 ...
- Node.js + Consul 实现服务注册、健康检查、配置中心
Node.js + Consul 实现服务注册.健康检查.配置中心 在这篇文章中: 初始化 Consul 客户端 服务注册与健康检查 配置Consul管理控制台 服务配置中心实现 在Nodejs中进行 ...
- mac环境搭建node.js并启服务
1.node官网下载并安装(https://nodejs.org/en/) 2.node -v //查看版本 3.安装成功后后在Finder中打开用户目录(就是Mac管理员,点开侧栏创建一个Js文件 ...
- 为一个 iOS 应用编写一个简单的 Node.js/MongoDB Web 服务
原文链接:https://github.com/nixzhu/dev-blog/blob/master/2014-04-21-write-a-simple-nodejs-mongodb-web-ser ...
- 基于 Node.js 爬虫的数据 API,搭建一套属于自己的 API 数据
SpliderApi https://github.com/ecitlm/Spl... 基于nodejs 的爬虫 API接口项目,包括前端开发日报.知乎日报.前端top框架排行.妹纸福利.搞笑视频/ ...
- node mysql做项目视频教程_2018最新 自学Node/Node.js/Nodejs视频教程 后端框架Express项目实战...
课程简介 这是一套完整零基础学习Node.js全栈开发的视频教程. 教程到的内容包括: (1)JavaScript基础(基本语法.数据类型.操作符.语句.对象.Math对象等) (2)Node.js基 ...
- node.js创建WebSocket服务,并使用原生js ES6完成对WebSocket数据交互
注意,前情提示: 本代码基于<Node.js(nodejs)对本地JSON文件进行增.删.改.查操作(轻车熟路)> 传送门Node.js(nodejs)对本地JSON文件进行增.删.改.查 ...
- 将node.js程序作为服务,并在windows下开机自动启动(使用forever)
手上项目中有一块服务是用node.js实现的,运行环境是windows server 2008 R2,刚开始着手实现这块功能的时候时间很紧迫,随便写了个console程序就部署上去了--启动方式就是在 ...
最新文章
- 解密FFmpeg播放track mode控制
- SketchUp(草图大师) 2019 安装教程
- 关于印发《会计电算化管理办法》等规章的通知
- Web前端必备-Nginx知识汇总
- Java黑皮书课后题第3章:*3.32(几何:点的位置)给定一个从点p0(x0,y0)到p1(x1,y1)的有向线段,可以用以下公式判定定点p2(x2, y2)是在线段的左侧、右侧,或者在该线段上
- 暑假做题记录【实时更新】
- hive启动mapreduce任务后,被killed
- php 查询and or,php – SQL查询多个AND和OR不起作用
- 学会拒绝别人的6个技巧_多少人败在不懂拒绝上!牢记10个高情商拒绝技巧,人生越来越顺...
- 今天的快乐从何而来的飞鸽传书
- Python数据分析-初识numpy、pandas、scipy、matplotlib和Scikit-Learn等数据处理库
- php框架大全图解_PHP框架汇总 - 鱼煎的个人空间 - OSCHINA - 中文开源技术交流社区...
- linux svn 安装信息,linux 下安装 subversion(svn) 客户端
- 递归算法设计 —— 选择排序和冒泡排序
- 敏捷开发免费管理工具——火星人预览(四)
- 解决jquery中全选点击第二次不生效的问题与分析
- tomcat按日期分割日志(官网文档推荐实现)
- 用户手册 (V4.0 版)
- 基于pytorch的花卉识别小程序
- Springboot毕业设计毕设作品,黑白图片大全和AI智能上色系统
热门文章
- 60 SD配置-科目分配-分配总帐科目
- C语言 memcpy函数(增加dst 从第一字节拷贝判断)的内部简单实现方式
- usb连接不上 艾德克斯电源_STM32F7 电源控制器(PWR)
- QT:不停的提示“文件已改变”
- OpenCV Mat主要用法(2)_MatExpr
- pix2pix, CycleGAN和pix2pixHD(没有公式,容易理解)
- 边缘计算:万物互联时代新型计算模型
- android 搭建短信平台,Android 短信SDK集成文档 | Mob文档中心
- c语言位向量机伞_一文读懂C语言精华-指针变量和指向指针的指针
- 解决Vue报错:Uncaught (in promise) NavigationDuplicated: Avoided redundant navigation to current location