Express
和Koa
是Node.js
社区广发使用的框架,简单且扩展性强,非常适合做个人项目,但框架本身缺少约定,标准的MVC模型会有各种千奇百怪的写法,Egg.js
相比Express和Koa更规范一些,Egg.js
按照规定进行开发,内置多进程管理,进行Koa
开发,性能优异,具有高度可扩展的插件机制,框架稳定,并提供基于Egg.js
定制上层框架的能力。
Egg.js
基于Es6
、Es7
以及Typescript
、Koa2
,使得Nodejs
具有更规范的开发模式、更低的学习成本、更优雅的代码、更少的开发成本、更少的维护成本,它是为企业级框架而生!
##安装egg
脚手架以及使用egg-init
创建项目
方法一:
npm i egg-init -g
// egg-example 是项目名字
egg-init egg-example --type=simple
cd egg-example
npm i
运行项目:
npm run dev
方法二
mkdir egg-example && cd egg-example
npm init-egg --type=simple
npm i
运行项目:
npm run dev
Vscode插件egg
Egg Tools
可以是快速使用Egg.js
语法,更加灵活使用
Egg-view-ejs
npm i egg-view-ejs --save
// 使用插件须在config/plugin.js进行配置
MVC框架
M:model
模型(service
) 和数据打交道(查询数据库/操作数据库/请求数据)处理复杂的业务逻辑以及数据操作
V:view
视图 模板 页面的展示
C: controller
控制器负责处理业务逻辑的处理 (简单业务员逻辑处理)
项目目录概念
-
app
- controller: 控制器 负责处理一些业务逻辑的处理
- pubilc:放置静态资源文件
- view: 视图 模板 页面的展示
- service: (
Model
)模型主要和数据打交道(查询数据库 请求数据) - middleware: 中间件 处理路由配置之前和之后逻辑和一些权限处理
- extend: 定义一些方法
- router.js:存放路由配置
controller
每一次用户请求,框架都会实例化对应的
Service
实例,由于它继承与egg.Service
,故拥有下列属性方便我们进行开发
- this.ctx:当前请求的上下文
Context
对象的实例,通过它我们可以拿到框架封装好的处理当前请求的各种便捷属性和方法 - this.app: 当前应用
Application
对象的实例,通过它我们可以拿到框架提供的全局对象和方法 - this.service: 应用定义的
Service
,通过它我们可以访问到抽象出的业务层,等价于this.ctx.service
- this.config:应用运行时的配置
- this.logger:logger 对象,上面有四个方法(
debug
,info
,warn
,error
),分别代表打印四个不同的日志,使用方法和效果与content
logger
中介绍的一样,但是通过这个logger
对象记录的日志,在日志前面会加上打印该日志的文件路径,以便快速定位日志打印位置
Service
Service文件必须放在 app/service 目录,可以支持多级目录,访问的时候可以通过名录名级联访问。
extend
egg
框架会把app/extend/application.js中定义的对象与Koa Application
的prototype对象进行合并,在应用启动时会基于扩展后的prototype
生成app对象
middleware
匹配路有前、匹配路由完成做的一些列操作。Egg时基于Koa实现的,所以Egg的中间件形式和Koa的中间件是一样的,都是基于洋葱圈模型。
配置
一般来说中间件也会有自己的配置。在框架中,一个完整的中间件是包含了配置处理的。我们约定一个中间件是一个放置在 app/middleware 目录下的单独文件,它需要exports
一个普通的function
,接受两个参数:
- options: 中间件的配置项,框架会将 app.config[${middlewareName}] 传递进来。
- app: 当前应用 Application 的实例
CSRF
在JSONP
配置中,我们只需要打开csrf: true,
即可对JSONP
接口开启 CSRF 校验。
// config/config.default.js
module.exports = {
jsonp: {
csrf: true,
},
};
注意,CSRF 校验依赖于 security 插件提供的基于 Cookie 的 CSRF 校验。
在开启 CSRF 校验时,客户端在发起 JSONP 请求时,也要带上 CSRF token,如果发起 JSONP 的请求方所在的页面和我们的服务在同一个主域名之下的话,可以读取到 Cookie 中的 CSRF token(在 CSRF token 缺失时也可以自行设置 CSRF token 到 Cookie 中),并在请求时带上该 token。
// 增加配置中间件
config.middleware = ['printdate', forbidip] // 这个时middleware目录下问文件名字,并非方法名字
// 给中间件传入参数
config.printdate = {
a:"String",
b:"Booleran"
}
Cookie
ctx.cookies.set(key, value, options)
设置 Cookie 其实是通过在 HTTP 响应中设置 set-cookie 头完成的,每一个 set-cookie 都会让浏览器在Cookie
中存一个键值对。在设置 Cookie 值的同时,协议还支持许多参数来配置这个Cookie
的传输、存储和权限。
-
{Number} maxAge: 设置这个键值对在浏览器的最长保存时间。是一个从服务器当前时刻开始的毫秒数。
-
{Date} expires: 设置这个键值对的失效时间,如果设置了 maxAge,expires 将会被覆盖。如果 maxAge 和 expires 都没设置,Cookie 将会在浏览器的会话失效(一般是关闭浏览器时)的时候失效。
-
{String} path: 设置键值对生效的 URL 路径,默认设置在根路径上(/),也就是当前域名下的所有 URL 都可以访问这个 Cookie。
-
{String} domain: 设置键值对生效的域名,默认没有配置,可以配置成只在指定域名才能访问。
-
{Boolean} httpOnly: 设置键值对是否可以被 js 访问,默认为 true,不允许被 js 访问。
-
{Boolean} secure: 设置键值对只在 HTTPS 连接上传输,框架会帮我们判断当前是否在 HTTPS 连接上自动设置 secure 的值。
除了这些属性之外,框架另外扩展了 3 个参数的支持: -
{Boolean} overwrite:设置 key 相同的键值对如何处理,如果设置为 true,则后设置的值会覆盖前面设置的,否则将会发送两个 set-cookie 响应头。
-
{Boolean} signed:设置是否对 Cookie 进行签名,如果设置为 true,则设置键值对的时候会同时对这个键值对的值进行签名,后面取的时候做校验,可以防止前端对这个值进行篡改。默认为 true。
-
{Boolean} encrypt:设置是否对 Cookie 进行加密,如果设置为 true,则在发送 Cookie 前会对这个键值对的值进行加密,客户端无法读取到 Cookie 的明文值。默认为 false。
在设置 Cookie 时我们需要思考清楚这个 Cookie 的作用,它需要被浏览器保存多久?是否可以被 js 获取到?是否可以被前端修改?
默认的配置下,Cookie
是加签不加密的,浏览器可以看到明文,js 不能访问,不能被客户端(手工)篡改。
如果想要 Cookie 在浏览器端可以被 js 访问并修改:
ctx.cookies.set(key, value, {
httpOnly: false,
signed: false,
});
// 重新设置cookie的Key为null 也相当于清理Cookie
this.ctx.cookies(ket,null)
this.ctx.redirect('/index') // 路由跳转
- Cookie可以实现 同一个浏览器访问同一个域的时候, 不同页面之间的数据共享
- 实现数据的持久化 (关闭浏览器重新打开以后数据还存在)
Session
需要 特别注意 的是:设置 session 属性时需要避免以下几种情况(会造成字段丢失,
不要以 _ 开头
不能为 isNew
// ❌ 错误的用法
ctx.session._visited = 1; // --> 该字段会在下一次请求时丢失
ctx.session.isNew = 'HeHe'; // --> 为内部关键字, 不应该去更改
// ✔️ 正确的用法
ctx.session.visited = 1; // --> 此处没有问题
Session
的实现是基于Cookie
的,默认配置下,用户 Session
的内容加密后直接存储在Cookie
中的一个字段中,用户每次请求我们网站的时候都会带上这个 Cookie,我们在服务端解密后使用。Session
的默认配置如下:
config.session = {
key: 'EGG_SESS',
maxAge: 24 * 3600 * 1000, // 1 天
httpOnly: true,
encrypt: true,
};
Session
的使用方法非常直观,直接读取它或者修改它就可以了,如果要删除它,直接将它赋值为null
:
ctx.session = null;
语法
// 获取get传值
cosnt qyery = this.ctx.query
// 获取动态路由传值
const params = this.ctx.params
// 注意 ctx是异步
await this.ctx.render('index') // index:指的是你要渲染view文件下的名字 渲染view里面的模板视图
// <%=msg%>: 模板引擎
// app/service
var response = await this.ctx.curl(api, method) //
// app/service
const Service = require('egg').Service;
class NewService extends Service {
async getNewList() {
const list = [1,2,3]
return list
}
}
一个控制器(controller)可以调用多个服务(service),服务(service)之间亦可以相互调用。
评论区