创建egg应用
安装egg
npm init egg --type=simple
进入项目cd myegg
安装依赖npm install
启动应用npm run dev
安装egg-mongoose
npm install egg-mongoose --save
config 文件夹修改 config.default.js
// 配置链接mongodb路径参数
config.mongoose = {
client: {
url: 'mongodb://123:123@168.1.0.1/dcw',
options: {},
},
};
需修改plugin.js
module.exports = {
// had enabled by egg
// static: {
// enable: true,
// }
// 启用mongodb
mongoose: {
enable: true,
package: 'egg-mongoose',
},
// keys: 'dcw',
};
创建controle server modle router
controller 文件夹创建 user.js
'use strict';
// 从egg 取controller 实例
const Controller = require('egg').Controller;
class UserController extends Controller {
async getUserList() {
const { ctx, service } = this;
// 获取service 业务逻辑数据
const mockList = await service.user.find();
ctx.body = {
code: 1,
msg: 'success',
data: mockList,
};
}
}
module.exports = UserController;
service 文件夹创建user.js
'use strict';
const Service = require('egg').Service;
class UserService extends Service {
async find() {
// 从数据库模型拿取查询数据
const mockList = await this.ctx.model.User.find({}, (d, s) => {
// console.log(d, s);
});
return Object.assign({}, {
pageNum: 1,
pageSize: 10,
list: mockList,
});
}
}
module.exports = UserService;
model 文件夹创建user.js
'use strict';
module.exports = app => {
// 创建mongoose实例 创建Ausers 表
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
// 创建表字段及类型
const UserSchema = new Schema({
userName: { type: String },
passWord: { type: String },
});
const User = mongoose.model('Ausers', UserSchema);
return User;
};
本地开发
需要把 egg-bin 模块作为 devDependencies 引入
npm i egg-bin --save-dev
启动应用
添加 npm scripts 到 package.json
{
"scripts": {
"dev": "egg-bin dev"
}
}
可以通过 npm run dev 命令启动应用
环境配置
本地启动的应用是以 env: local 启动的,读取的配置也是 config.default.js 和 config.local.js 合并的结果
config 配置
egg提供5种配置文件:
- config.default.js:默认配置文件;
- config.local.js:开发环境下的配置,与默认配置合并,同名则覆盖默认配置;
- config.prod.js:生产环境下的配置,与默认配置合并,同名则覆盖默认配置;
- config.test.js:测试环境下的配置,与默认配置合并,同名则覆盖默认配置;
- config.unittest.js:单元测试环境下的配置,与默认配置合并,同名则覆盖默认配置;
指定端口
本地启动应用默认监听 7001 端口,可指定其他端口,例如:
{
"scripts": {
"dev": "egg-bin dev --port 7002"
}
}
router 创建知识点
router.resources('users', '/api/users', controller.users)好处相当于定义了一组RESTful的路由: 如下面7个路由
router.get("/api/users", controller.users.index);
router.get("/api/users/new", controller.users.new);
router.get("/api/users/:id", controller.users.show);
router.get("/api/users/:id/edit", controller.users.edit);
router.post("/api/users", controller.users.create);
router.put("/api/users/:id", controller.users.update);
router.delete("/api/users/:id", controller.users.destroy);
中间件(Middleware)洋葱模型
编写两个测试中间件middleware1和middleware2
// middleware/middleware1.js
module.exports = (options, app) => {
return async function middleware1(ctx, next) {
console.log("==request one==");
await next();
console.log("==response one==");
}
};
// middleware/middleware2.js
module.exports = (options, app) => {
return async function middleware2(ctx, next) {
console.log("==request two==");
await next();
console.log("==response two==");
}
};
options:中间件的参数,可在Config中配置; app和ctx上面也说过了,有这两个对象在中间件中可以搞好多事,比如可以拿到ctx.request对参数进行修改等; next为一个函数,下面会说作用。
写完中间件之后是需要在config.default.js中进行配置:
// config/config.default.js
exports.middleware = ['middleware1', 'middleware2']; // 数组的顺序为中间件执行的顺序
exports.middleware1 = { // 中间件参数(即options)
msg: "extra message"
}
扩展(Extend)文件夹
框架的很多对象都是支持扩展的,我们可以在很多对象上扩展自定义的属性和方法,可扩展的对象有:Application、Context、helper、Request和Response。 编写扩展的方法就是创建对应的文件,之后会与原对象进行合并对象的prototype上,以此实现了扩展的功能,在extend文件夹下创建扩展 application.js application.prod.js 为什么application会有2个扩展文件呢?看到这个命名应该就能猜到了,实际上egg也支持按照环境扩展,所以我们可以在特定的环境下扩展需要的功能。
日志
在Controller、Service中使用日志时,可直接使用,this.logger,有none,warn,info,debug,error等方法。默认目录在项目下logs,其结构为:demo/logs/demo/…,默认以eggjs开头的日志后跟日志的生成者。日志的生成路径及大小可以在demo/app/config/config.${env}.js中进行配置,配置内容如下:
exports.logger = {
dir:'',//配置日志生成路径
level:'DEBUG',//日志级别
//....其它
}
定时发布器
定时任务所在文件夹:/app/schedule
const Subscription = require('egg').Subscription;
class schedule1 extends Subscription{
//设置定时任务信息
static get schedule(){
return {
interval:'1m',//设置时间间隔
type:'all'//所有worker都执行
}
}
//要执行的内容
async subscirbe(){
this.logger.info(123);
}
}
Cookie
通过 ctx.cookies,我们可以在 controller 中便捷、安全的设置和读取 Cookie
class UserController extends Controller {
async add() {
const ctx = this.ctx;
let count = ctx.cookies.get('count');
count = count ? Number(count) : 0;
ctx.cookies.set('count', ++count);
ctx.body = count;
}
async remove() {
const ctx = this.ctx;
ctx.cookies.set('count', null);
ctx.status = 204;
}
}
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 的值
-
{Boolean} overwrite:设置 key 相同的键值对如何处理,如果设置为 true,则后设置的值会覆盖前面设置的,否则将会发送两个 set-cookie 响应头
-
{Boolean} signed:设置是否对 Cookie 进行签名,如果设置为 true,则设置键值对的时候会同时对这个键值对的值进行签名,后面取的时候做校验,可以防止前端对这个值进行篡改。默认为 true
-
{Boolean} encrypt:设置是否对 Cookie 进行加密,如果设置为 true,则在发送 Cookie 前会对这个键值对的值进行加密,客户端无法读取到 Cookie 的明文值。默认为 false
// 设置样例
ctx.cookies.set(key, value, {
httpOnly: false,
signed: false,
});
// 获取样例
ctx.cookies.get(key, options)
Cookie 秘钥
由于我们在 Cookie 中需要用到加解密和验签,所以需要配置一个秘钥供加密使用。在 config/config.default.js 中
module.exports = {
keys: 'key1,key2',
};
keys 配置成一个字符串,可以按照逗号分隔配置多个 key。Cookie 在使用这个配置进行加解密时:
-
加密和加签时只会使用第一个秘钥。
-
解密和验签时会遍历 keys 进行解密。
如果我们想要更新 Cookie 的秘钥,但是又不希望之前设置到用户浏览器上的 Cookie 失效,可以将新的秘钥配置到 keys 最前面,等过一段时间之后再删去不需要的秘钥即可。
Session
框架内置了 Session 插件,给我们提供了 ctx.session 来访问或者修改当前用户 Session
class UserController extends Controller {
async getPosts() {
const ctx = this.ctx;
// 获取 Session 上的内容
const userId = ctx.session.userId;
const posts = await ctx.service.post.fetch(userId);
// 修改 Session 的值
ctx.session.visited = ctx.session.visited ? (ctx.session.visited + 1) : 1;
ctx.body = {
success: true,
posts,
};
}
}
修改session, 如果要删除它,直接将它赋值为 null
// 设置
ctx.session.user ='xiaodoubao'
// 删除
ctx.session = null;
设置session 注意事项
-
不要以 _ 开头
-
不能为 isNew
// ❌ 错误的用法
ctx.session._visited = 1; // --> 该字段会在下一次请求时丢失
ctx.session.isNew = 'HeHe'; // --> 为内部关键字, 不应该去更改