Egg.js使用

egg.js

  • 基于 Koa 开发,性能优异
  • node版本 >= 8.x

创建项目

使用脚手架

- 初始化
$ mkdir egg-example && cd egg-example
$ npm init egg --type=simple
$ npm i
- 运行
$ npm run dev
$ open http://localhost:7001

- 手动搭建

- 初始化下目录结构
$ mkdir egg-demo , cd egg-demo
$ npm init
$ npm i egg --save
$ npm i egg-bin --save-dev
- 添加 npm scripts
package.json:
{
  "name": "egg-demo",
  "scripts": {
    "dev": "egg-bin dev"
  }
}
- 编写 Controller
// app/controller/home.js
const Controller = require('egg').Controller;

class HomeController extends Controller {
  async index() {
    this.ctx.body = 'Hello world';
  }
}

module.exports = HomeController;
- 配置路由映射:
// app/router.js
module.exports = app => {
  const { router, controller } = app;
  router.get('/', controller.home.index);
};
- 添加配置文件
// config/config.default.js
exports.keys = <此处改为你自己的 Cookie 安全字符串>;
- 当前目录结构
egg-example
├── app
│   ├── controller
│   │   └── home.js
│   └── router.js
├── config
│   └── config.default.js
└── package.json
- 启动应用
$ npm run dev
$ http://localhost:7001

路由(Router)

- app/router.js:
module.exports = app => {
  const { router, controller } = app;
  router.get('/user/:id', controller.user.info);
};

- 对应controller: app/controller/user.js
class UserController extends Controller {
  async info() {
    const { ctx } = this;
    ctx.body = {
      name: `hello ${ctx.params.id}`,
    };
  }
}

- 内置基础对象

- Context
常见的 Context 实例获取方式是在 Middleware, Controller 以及 Service

创建一个匿名 Context 实例
// app.js
module.exports = app => {
  app.beforeStart(async () => {
    const ctx = app.createAnonymousContext();
    // preload before app start
    await ctx.service.posts.load();
  });
}

在定时任务中的每一个 task 都接受一个 Context 实例作为参数
// app/schedule/refresh.js
exports.task = async ctx => {
  await ctx.service.posts.refresh();
};
- Request & Response
Request(ctx.request) 和 Response(ctx.response) 

// app/controller/user.js
class UserController extends Controller {
  async fetch() {
    const { app, ctx } = this;
    const id = ctx.request.query.id;
    ctx.response.body = app.cache.get(id);
  }
}
- Controller & Service
    ctx - 当前请求的 Context 实例。
    app - 应用的 Application 实例。
 config - 应用的配置。
service - 应用所有的 service。
 logger - 为当前 controller 封装的 logger 对象
 
通过两种方式来引用 Controller 基类

- 从 egg 上获取(推荐):app/controller/user.js

const Controller = require('egg').Controller;
const Service = require('egg').Service;

class UserController extends Controller {
  // implement
}
module.exports = UserController;

class UserService extends Service {
  // implement
}
module.exports = UserService;

- 从 app 实例上获取
module.exports = app => {
  return class UserController extends app.Controller {
    // implement
  };
};

module.exports = app => {
  return class UserService extends app.Service {
    // implement
  };
};
- logger
日志功能
logger.debug()
logger.info()
logger.warn()
logger.error()

获取: 
app.logger | app.coreLogger 
ctx.logger | ctx.coreLogger
this.logger(Controller Logger & Service Logger)
- Subscription
订阅模型
const Subscription = require('egg').Subscription;

class Schedule extends Subscription {
  // 需要实现此方法
  // subscribe 可以为 async function 或 generator function
  async subscribe() {}
}
- Config 配置
获取:app.config
- Helper
 Helper(ctx.helper) 
 
- app/controller/user.js
class UserController extends Controller {
  async fetch() {
    const { app, ctx } = this;
    const id = ctx.query.id;
    const user = app.cache.get(id);
    ctx.body = ctx.helper.formatUser(user);
  }
}

自定义 helper 方法
- app/extend/helper.js
module.exports = {
  formatUser(user) {
    return only(user, [ 'name', 'phone' ]);
  }
};

属性

  • vscode插件:eggjs

  • 主文件目录

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rehvzul0-1633744809058)(img/image-20201125110410442.png)]

- router

const { router, controller } = app;
router.get('/', controller.home.index);
// 动态路由
router.get('/demoList/:id', controller.demo.demoList);

// post请求
router.post('/from', controller.home.add);

home对应文件名
home.index -> async index()

请添加图片描述

- controller

处理业务逻辑
快捷生成:egg controller

async index() {
    const { ctx } = this;
    ctx.body = 'hi, egg demo';
    
    // 获取get传值: ctx.query
    // 获取动态路由值:ctx.params

    // 渲染模板:xxx.html
    await ctx.render('xxx', {
        msg: 'ejs模板渲染传值',
    });
    
    // 调用service服务, demo对应 app/service/demo.js
    const list  = await ctx.service.demo.getList();
    
    // 调用extend里面扩展的application
    ctx.app.foo()
    // 调用extend里面扩展的helper
    ctx.helper.formatTime('1406541849')
    
    // 设置cookie: ctx.cookie.set(key, value, options)
    // 获取cookie: ctx.cookie.get(key, options)
    // 清除cookie: ctx.cookie.set(key, null)
    
    // 路由跳转重定向: ctx.redirect('/')
    
    // 设置session: ctx.session.key = 'xxx'
    // 获取session: ctx.session.key
}

- view

渲染模板:app/views/xxx.html
controller中引入渲染
egg ejs: https://github.com/eggjs/egg-view-ejs

安装: npm i egg-view-ejs --save
配置:
- config/plugin.js:
    ejs: {
      enable: true,
      package: 'egg-view-ejs',
    };

- config/config.default.js
    config.view = {
      mapping: {
        '.html': 'ejs',
      },
    };  
获取controller 传值渲染
  - 简单值:hello <%= msg %>
  - for循环
    
    <%for(var i = 0; i < list.length; i++){%>
  • <%=list[i]%>
  • <%}%>
- img - 调用:app/extend/helper.js 方法 <%=helper.formatTime(dateline)%>

- service

(app/service):查询数据库

快捷生成:egg service

// curl方法: 获取远程的数据(通过接口抓取数据)
const resp = await ctx.curl(api)
console.log(resp.data)   //   

// 处理将Buffer(16进制)转换为对象
const data = JSON.parse(resp.data)
demo:

- middleware

Egg.js使用_第1张图片

中间件:处理(app/ middleware/xx.js)

exports 一个普通的 function(options, app){...}
 	- options: 中间件的配置项,传递app.config[${middlewareName}]
	- app: 当前应用 Application 的实例。


在应用中使用, config.default.js:
    module.exports = {
      // 配置需要的中间件,数组顺序即为中间件的加载顺序
      middleware: [ 'gzip' ],

      // 传递给 gzip 中间件的参数
      gzip: {
        threshold: 1024, // 小于 1k 的响应体不压缩
      },
    };

router 中使用:
	const gzip = app.middleware.gzip({ threshold: 1024 });
    app.router.get('/needgzip', gzip, app.controller.handler);

- extends

扩展: https://eggjs.org/zh-cn/basics/extend.html
- app/extend/
- 时间戳转换为日期

- application.js
    module.exports = {
      foo() {},
    }
    - 外部调用:ctx.app.foo()
    
- helper.js
	// 扩展引入第三方模块: silly-datetime
    const sd = require('silly-datetime')
    module.exports = {
        formatTime(param) {
            // 格式化时间戳
            return sd.format(new Date(param*1000), 'YYYY-MM-DD HH:mm')
        }
    }
    - 外部调用 :ctx.helper.formatTime('1406541849')
    - view/xx.html中调用:<%=helper.formatTime(dateline)%>

- context.js
	- 外部调用 :ctx.context.foo()
	
- request.js
	- 外部调用 :ctx.request.foo()
	
- response.js
	- - 外部调用 :ctx.response.foo()

- post & CSRF防范

post :
	获取数据: ctx.request.body
    
用户名:
密 码:
submit 后报错:"invalid csrf token" 解决:使用CSRF防范

- CSRF防范

获取:ctx.csrf (用户访问后会生成一个密钥)

解决err("invalid csrf token"): 
	- 传递csrf or 设置全局变量
	设置 action="/addFrom?_csrf=<%=csrf%>"

- 配置模板全局变量

middleware/xx.js

// 设置全局模板变量
ctx.state.csrf = ctx.csrf

- cookie

cookie: 
	- 实现同一个浏览器同域名时,不同页面之间的数据共享
	- 实现数据持久化
	- 默认浏览器关闭即销毁,但是可设置过期时间

设置:ctx.cookie.set(key, value, options)
获取:
	未加密:ctx.cookie.get(key)
	加密后:ctx.cookie.get(key, { encrypt: true })

默认设置中文值:err
	解决:添加加密属性即可:encrypt: true

清除cookie(2种): 
	- ctx.cookie.set(key, null)
	- ctx.cookie.set(key, null, { maxAge: 0 })

options:
	- maxAge {Number(毫秒数)}: 设置这个键值对在浏览器的最长保存时间
	- expires {Date}: 设置这个键值对的失效时间
		- 如果设置了 maxAge,expires 将会被覆盖。
		- 如果 maxAge 和 expires 都没设置,关闭浏览器时失效
		
	- path {String: 根路径上(/)}: 设置键值对生效的 URL 路径
	- domain {String: 尾配置}: 设置键值对生效的域名(可配置只在指定域名才能访问)
	- httpOnly {Boolean: true(不允许)}: 设置键值对是否可以被 js 访问
	
	- secure {Boolean}: 设置键值对只在 HTTPS 连接上传输
	- overwrite {Boolean:false}:设置 key 相同的键值对
		- true: 后设置的值会覆盖前面设置的,
		- false: 会发送两个 set-cookie 响应头
		
	- signed {Boolean:true}:设置是否对 Cookie 进行签名
		- true: 防止用户修改,修改后将失效不可获取
		        
	- encrypt {Boolean:false}:设置是否对 Cookie 进行加密,
		- true: 则在发送 Cookie 前会对这个键值对的值进行加密
			    客户端无法读取到 Cookie 的明文值
			    
默认设置中文值:

Egg.js使用_第2张图片

- session

```
session属性与cookie基本一样

设置: ctx.session.key = '...' || {...}
获取: ctx.session.key

设置属性: 
	- 不建议:ctx.session.maxAge = 60*1000
	- config.default.js设置(建议):见下图

session默认设置:
```

Egg.js使用_第3张图片
Egg.js使用_第4张图片


mysql

基础配置

```
- 安装插件npm i --save egg-mysql

- 开启插件: config/plugin.js
mysql: {
  enable: true,
  package: 'egg-mysql',
};

- config/config.${env}.js 配置各个环境的数据库连接信息
```

数据源

- 单数据源
```
config/config.${env}.js

exports.mysql = {
    // 单数据库信息配置
    client: {
        host: 'mysql.com',
        port: '3306',
        user: 'test_user',
        password: 'test_password',
        // 数据库名
        database: 'test',
    },
    // 是否加载到 app 上,默认开启
    app: true,
    // 是否加载到 agent 上,默认关闭
    agent: false,
    // 开启日志sql
    debug: true
};

单实例使用: await app.mysql.query(sql, values);
```
- 多数据源
```
exports.mysql = {
  clients: {
    // clientId, 获取client实例,需要通过 app.mysql.get('clientId') 获取
    db1: {
      host: 'mysql.com',
      port: '3306',
      user: 'test_user',
      password: 'test_password',
      database: 'test',
    },
    db2: {
      host: 'mysql2.com',
      port: '3307',
      user: 'test_user',
      password: 'test_password',
      database: 'test',
    },
    // ...
  },
  // 所有数据库配置的默认值
  default: {},
  // 是否加载到 app 上,默认开启
  app: true,
  // 是否加载到 agent 上,默认关闭
  agent: false,
};

使用: 
const client1 = app.mysql.get('db1');
await client1.query(sql, values);
```

操作

```
Service: app/service/user.js
	await this.app.mysql.get('users', { id: 11 });
	
Controller: app/controller/user.js
	await ctx.service.user.find(ctx.params.id)
```

CRUD 语句

- router

Egg.js使用_第5张图片

- Read
查询一条记录: await this.app.mysql.get('users', { id: 12 });
   查询全表: await this.app.mysql.select('users');

条件查询和结果定制:
const results = await this.app.mysql.select('users', {
  where: { status: 'draft', author: ['author1', 'author2'] },
  columns: ['author', 'title'],                   // 要查询的表字段
  orders: [['created_at','desc'], ['id','desc']], // 排序方式
  limit: 10, // 返回数据量
  offset: 0, // 数据偏移量
});
- insert
await this.app.mysql.insert('users', { 
	title: 'Hello World' 
});
- Update
const row = {
  id: 123,
  name: 'fengmk2'
};
const result = await this.app.mysql.update('users', row);
- Delete
await this.app.mysql.delete('users', {
  author: 'fengmk2',
});
- 执行 sql 语句
查询
const post = await this.app.mysql.get('posts', { id: 12 });

ORM 框架

- 初始配置

安装: npm install --save egg-sequelize mysql2

config/plugin.js:
    // 引入 egg-sequelize 插件
    sequelize: {
      enable: true,
      package: 'egg-sequelize',
    };

config/config.default.js
    // sequelize 配置
    config.sequelize = {
      dialect: 'mysql',
      host: '127.0.0.1',
      port: 3306,
      database: 'egg-sequelize-doc-default',
    };

err

  • getaddrinfo ENOTFOUND
    config.mysql = {
        client: {
            host: "7003", 改为 'localhost',
        },
      }
    

你可能感兴趣的:(react,node,egg,javascript,node.js,react.js,前端框架)