史上最全Egg.js速查文档

1,088 阅读6分钟

eggjs.org/zh-cn/

一、创建项目

1、全局安装

npm i egg-init -g

2、初始化项目

新建项目文件夹后,npm init egg --type=simple

3、安装依赖

npm install

4、启动

测试:npm run dev

正式:npm run start

\

二、架构介绍(app)

eggjs是一个mvc的框架,约定优于配置

1、service

模型,和数据打交道,查询数据库、请求数据。(eggjs中service属于mvc架构中的model)

(1)controller获取service数据

const list = await this.service.news.getNewsList();

(2)service之间可以互相调用

(3)this.ctx.curl(url,{}) 发起网络调用

2、view

模版渲染,用于视图、模版、页面的展示。

(1)ejs的使用

www.yuque.com/cqcode/cdsm…

3、controller

this.ctx.body 用于返回数据

this.ctx.query 获取query的值

this.ctx.params 获取动态路由传值

this.ctx.request.body 用于获取post等方式的body请求数据

await this.ctx.render('news',{a:1,b:2}) 调用render渲染文件,并传递数据

4、router.js

用于路由配置

5、middleware(中间件)

中间件,加载路由前进行权限判断

(1)全局中间件的使用

//config.default.js 访问全部路由都会生效
config.middleware = ["auth"];

传参

//config.default.js
config.auth={
  title:"this is title"
}

//middleware auth.js
module.exports = (option,app)=>{
  return async function auth(ctx,next){
    console.log(option);
    console.log(new Date());
    await next();
  }
}

(2)路由中中间件的使用

//router.js
var auth = app.middleware.auth({title:"router title"});

router.get('/', auth, controller.home.index);

(3)框架中间间的默认配置

config.bodyParser = {
	jsonLimit: '10mb' //default is 1mb
}

(4)使用koa中间件

规范的koa中间件

//1、安装
npm install koa-jsonp

//2、middleware/jsonp.js
var jsonp = require('koa-jsonp');
module.exports = jsonp;

//3、config.default.js
config.middleware = ['jsonp'];

koa-compress //用于压缩页面大小,加快响应速度

//3、config.default.js
config.compress = {
  threshold:100 //它支持指定只有当body大于配置的threshold时,才进行gzip压缩,默认1024
}

非标准的koa中间件 (包含多个option)

//middleware/Middleware.js
const Middleware = require('some-koa-middleware');
module.exports = (option,app)=>{
	return Middleware(option.xxx,option.xxx);
}

(5)中间件通用属性

enable:控制中间件是否开启。

match:设置只有符合某些规则的请求才会经过这个中间件。

ignore:设置符合某些规则的请求不经过这个中间件。

match和ignore不能同时使用

//普通使用
config.auth = {
  enable:false,
  match:'/news',
  title:'随便一个传参'
}
//高级使用
config.auth = {
  enable:true,
  match(ctx){
  	if(ctx.request.url == "/shop" || ctx.request.url == "/news") return true;
    return false;
  },
  title:'随便一个传参'
}

\

6、extend

对application、context、request、response、helper对象进行自定义拓展,进一步加强框架的功能

\

7、public

存放静态资源 访问方法 /public/xxx/xxx.xxx

\

8、定时任务(schedule)

(1)所有定时任务存放在app/schedule目录下

(2)使用方法

//标准写法
const Subscription = require('egg').Subscription;
var i = 0;
class Test extends Subscription{
  static get schedule() {
    return {
      interval: '3s', // 时间间隔
      type: 'all', // 指定所有的 worker(进程) 都需要执行
      disable:false //是否关闭定时任务,false不关闭
    };
  }

  // subscribe 是真正定时任务执行时被运行的函数
  async subscribe() {
    //定时任务执行的操作
    ++i;
    console.log(i);
  }
}

module.exports = Test;
//简单写法
module.exports = {
  schedule: {
    interval: '3s', // 3秒间隔
    type: 'all', // 指定所有的 worker 都需要执行
    disable:false //是否关闭定时任务,false不关闭
  },
  async task(ctx) {
    const result = await ctx.service.home.getNews();
    console.log(result);
  },
};
//动态配置定时任务

//config.default.js
config.scheduleTime = '3s'

//schedule/test.js
module.exports = app => {
  return{
    schedule: {
      interval: app.config.scheduleTime, // 1 分钟间隔
      type: 'all', // 指定所有的 worker 都需要执行
      disable:false //是否关闭定时任务,false不关闭
    },
    async task(ctx) {
      const result = await ctx.service.home.getNews();
      console.log(result);
    },
  }
};

(3)cron

通过 schedule.cron 参数来配置定时任务的执行时机,定时任务将会按照 cron 表达式在特定的时间点执行。cron 表达式通过 cron-parser 进行解析。

注意:cron-parser 支持可选的秒(linux crontab 不支持)

*    *    *    *    *    *
┬    ┬    ┬    ┬    ┬    ┬
│    │    │    │    │    |
│    │    │    │    │    └ day of week (0 - 7) (0 or 7 is Sun)
│    │    │    │    └───── month (1 - 12)
│    │    │    └────────── day of month (1 - 31)
│    │    └─────────────── hour (0 - 23)
│    └──────────────────── minute (0 - 59)
└───────────────────────── second (0 - 59, optional)

示例:

module.exports = {
  schedule: {
    // 每三小时准点执行一次
    cron: '0 0 */3 * * *',
  },
};

三、config(配置)

1、config.default.js

//配置项
config.api = "http://www.cqcode.cn"
//其他文件访问配置项
this.config.api

2、plugin.js

(1)引入插件方法

//例如引入ejs
module.exports = {
  ejs:{
    enable: true,
    package:'egg-view-ejs'
  }
};

四、mysql

mysql文档:www.yuque.com/cqcode/node…

1、安装和引入

(1)安装

npm i --save egg-mysql

(2)引入

// config/plugin.js
exports.mysql = {
  enable: true,
  package: 'egg-mysql',
};

2、连接数据库(单数据源)

// config/config.default.js
config.mysql = {
  // 单数据库信息配置
  client: {
    // host
    host: 'mysql.com',
    // 端口号
    port: '3306',
    // 用户名
    user: 'test_user',
    // 密码
    password: 'test_password',
    // 数据库名
    database: 'test',
  },
  // 是否加载到 app 上,默认开启
  app: true,
  // 是否加载到 agent 上,默认关闭
  agent: false,
};

3、查询

使用get查询一条,select查询符合条件的全部

const res = await app.mysql.select('order',{	
  where:{state:ctx.query.state}, // WHERE 条件
  columns: ['author', 'title'], // 要查询的表字段
  orders: [['created_at','desc'], ['id','desc']], // 排序方式
  limit: 10, // 返回数据量
  offset: 0, // 数据偏移量
});

4、插入

// 在 post 表中,插入 title 为 Hello World 的记录‘
const result = await this.app.mysql.insert('posts', { title: 'Hello World' }); 
// 判断插入成功
const insertSuccess = result.affectedRows === 1;

5、更新

// 1、修改数据,将会根据主键 ID 查找,并更新
const row = {
  id: 123,
  name: 'fengmk2',
  otherField: 'other field value',    // any other fields u want to update
  modifiedAt: this.app.mysql.literals.now, // `now()` on db server
};
  const result = await this.app.mysql.update('posts', row); // 更新 posts 表中的记录
// 判断更新成功
const updateSuccess = result.affectedRows === 1;


// 2、如果主键是自定义的 ID 名称,如 custom_id,则需要在 `where` 里面配置
const row = {
  name: 'fengmk2',
  otherField: 'other field value',    // any other fields u want to update
  modifiedAt: this.app.mysql.literals.now, // `now()` on db server
};

const options = {
  where: {
    custom_id: 456
  }
};
const result = await this.app.mysql.update('posts', row, options); // 更新 posts 表中的记录

6、删除

const result = await this.app.mysql.delete('posts', {
  author: 'fengmk2',
});

7、sequelize

www.sequelize.com.cn/

安装

npm i --save egg-sequelize
npm install --save mysql2

引入

//plugin.js
exports.sequelize = {
  enable: true,
  package: 'egg-sequelize',
};

exports.mysql = {
  enable: true,
  package: 'egg-mysql',
};

//config.default.js
config.sequelize = {
  delegate: 'model', // load all models to app.model and ctx.model
  baseDir: 'model', // load models from `app/model/*.js`
  dialect: 'mysql', // support: mysql, mariadb, postgres, mssql
  database: '',
  host: '',
  port: 3306,
  username: '',
  password: '',
  define: {
    freezeTableName: true,
  },
};

使用

//创建
const res = await ctx.model.AdBgmCls.create({
  cls: cls_name,
});
//批量创建
const res = await ctx.model.AdBgmCls.bulkCreate({
  cls: cls_name,
});
//查询
const res = await ctx.model.AdBgmCls.findOne({
  where: {
    id:task.id,
  },
});
//批量查询
const res = await ctx.model.AdBgm.findAll({
  where: {
    status: 0,
  },
  order: [
    ['create_time', 'DESC'],
    ['usage_count', 'DESC']
  ],
});

//查询并计数
findAndCountAll

//更新1 update
const res = await ctx.model.AdBgm.update({
  status: 1,
}, {
  where: {
    id,
  }
});
//更新2 save
const effect = await ctx.model.Effect.findOne({id});
if(effect && effect.status === 0) {
  effect.status = 1;
  await effect.save();
}

//插入或更新
const res = await ctx.model.AdBgmCls.upsert({
  cls: cls_name,
});
//删除
const result = await this.ctx.model.AdTplResult.destroy({
  where: {
    tpl_id,
  },
});

复杂使用

1、查询json长度不等于0 且 名字不等于陈琦的数据

SELECT * FROM `home` AS `home` 
WHERE NOT ((json_length(`data`) = 0 OR `home`.`name` = 'chenqi'));

⬇️

const res = await this.ctx.model.Home.findAll({
  attributes: ['name'],
  where:{
    [Op.not]:[
      {
        [Op.or]:[
          Sequelize.where(Sequelize.fn('json_length', Sequelize.col('data')), 0),
          {
            name:name
          }
        ]
      }
    ]
  }
});

model

'use strict';

module.exports = (app, model) => {
  const { STRING, INTEGER, DATE } = app.Sequelize;
  const AdBgm = model.define('ad_bgm', {
    id: {
      type: INTEGER,
      primaryKey: true,
      autoIncrement: true,
    },
    user_id: STRING,
    name: STRING,
    addr: STRING,
    size: STRING,
    cls: STRING,
    music_start_time: STRING,
    duration: STRING,
    usage_count: INTEGER,
    status: INTEGER, // 0 正常 1 删除
    create_time: DATE,
    update_time: DATE,
  }, {
    timestamps: false,
  });
  return AdBgm;
};

\

\

五、安全风险

eggjs.org/zh-cn/core/…

1、csrf

在config.default.js关闭或开启csrf

exports.security = {
  csrf: {
    enable: false,
  },
};

六、第三方包

1、moment.js

文档:momentjs.cn/docs/#/mani…

安装

npm i --save moment

引入

//在controller中引入
const moment = require('moment');

使用

const params = {
  ...ctx.request.body,
  createTime:moment().format('YYYY-MM-DD HH-dd-ss')
}

扩展

//增加日期
moment().add(1,'year').format('YYYY-MM-DD hh:mm:ss')

//减少日期
moment().subtract(1,'days').format('YYYY-MM-DD hh:mm:ss')

\

2、egg-jwt

安装

npm install egg-jwt --save

引入

//config/plugin.js
exports.jwt = {
  enable: true,
  package: "egg-jwt"
};

//config/config.default.js
config.jwt = {
  secret: "cqyyds"//自定义 token 的加密条件字符串
};

使用

//router.js 限制接口需要jwt验证,用户已经获取token后使用,限制无token用户
router.post('/order/changeState',jwt,controller.order.changeState);

//controller 登陆成功返回token
const token = app.jwt.sign({
  username: ctx.request.body.username //存放用于存储的用户数据,ctx.state.username可全局获取
}, app.config.jwt.secret);

ctx.body = token;

前端使用

headers:{
  // 切记 token 不要直接发送,要在前面加上 Bearer 字符串和一个空格
  'Authorization':`Bearer ${token}`
}

\

3、egg-cors(跨域问题解决)

安装

npm install egg-cors

配置

//config/plugin.js
exports.cors = {
  enable: true,
  package: 'egg-cors',
}

//config.default.js
config.security = {
  csrf: {
    enable: false,
    ignoreJSON: true
  },
  domainWhiteList: ['*'],//允许访问接口的白名单
};
config.cors = {
  origin:'*',
  allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH'
};

七、部署到服务器

1、配置端口号

//config.default.js
config.cluster = {
  listen: {
    port: 7001,
    hostname: '127.0.0.1',
    // path: '/var/run/egg.sock'
  }
}

2、发布

(1)去除node_modules移动项目到服务器

(2)cd到项目文件 如:cd /usr/local/nginx/server/catz-server

(3)npm install --production

(4)npm start

此时服务已经在配置好的端口号开启,但把此端口暴露出去是不安全的,需要通过nginx转发

3、配置nginx转发到端口

//cd /usr/local/nginx/conf/
server {
  listen       80;
  server_name  localhost;

  #charset koi8-r;

  #access_log  logs/host.access.log  main;

  location / {
    root   html;
    index  index.html index.htm;
  }
  
  location /api/blog/ {
    proxy_pass http://127.0.0.1:6001/;
  }

  location /api/catz/ {
    proxy_pass http://127.0.0.1:6002/;
  }
}

如未生效,重启nginx

nginx -s reload

4、参考链接

nginx:www.cnblogs.com/paul123/p/1…

eggjs发布:blog.csdn.net/qq_37162688…

八、标准化项目搭建

九、serverless构建eggjs

控制台:console.cloud.tencent.com/sls

1、安装serverless

npm install -g serverless

serverless -v

2、创建项目

serverless

3、部署

serverless deploy

4、serverless.yml 配置不上传文件

component: http
name: eggshop
inputs:
  src:
    src: ./
    exclude:
      - .env
      - .git
      - node_modules
  faas:
    runtime: Nodejs12.16
    framework: egg
    name: '${name}'
  apigw:
    protocols:
      - http
      - https
app: eggshop