控制器 
控制器作用 
Controller 负责解析用户的输入,处理后给前端返回相应的结果。
框架推荐的 Controller 层主要流程是:首先对用户通过 HTTP 传递过来的请求参数进行处理(校验、转换),然后调用对应的 service 方法处理业务,在必要时把 Service 的返回结果处理转换,使之满足用户需求,最后通过 HTTP 将结果响应给用户。具体步骤如下:
- 获取用户通过 HTTP 传递过来的请求参数。
- 校验、组装参数。
- 调用 Service 进行业务处理,必要时处理转换 Service 的返回结果,让它适应用户的需求。
- 通过 HTTP 将结果响应给用户。
简单案例 
js
const { Controller } = require("egg");
class HomeController extends Controller {
  async index() {
    const { ctx } = this;
    ctx.body = "hi, egg";
  }
}
module.exports = HomeController;- 真实案例
js
const { Controller } = require("egg");
class PostController extends Controller {
  async create() {
    const { ctx, service } = this;
    const createRule = {
      title: { type: "string" },
      content: { type: "string" },
    };
    // 校验和组装参数
    ctx.validate(createRule);
    const data = Object.assign(ctx.request.body, {
      author: ctx.session.userId,
    });
    // 调用 Service 进行业务处理
    const res = await service.post.create(data);
    // 响应客户端数据
    ctx.body = { id: res.id };
    ctx.status = 201;
  }
}
module.exports = PostController;ctx 对象 
在 Controller 中通过 this.ctx 可以获取上下文对象,方便获取和设置相关参数,例如:
- ctx.query:URL 中的请求参数(忽略重复 key)
- ctx.quries:URL 中的请求参数(重复的 key 被放入数组中)
- ctx.params:Router 上的命名参数
- ctx.request.body:HTTP 请求体中的内容
- ctx.request.files:前端上传的文件对象
- ctx.getFileStream():获取上传的文件流
- ctx.multipart():获取 multipart/form-data 数据
- ctx.cookies:读取和设置 cookie
- ctx.session:读取和设置 session
- ctx.service.xxx:获取指定 service 对象的实例(懒加载)
- ctx.status:设置状态码
- ctx.body:设置响应体
- ctx.set:设置响应头
- ctx.redirect(url):重定向
- ctx.render(template):渲染模板
继承基类 
举例
js
// app/core/base_controller.js
const { Controller } = require("egg");
class BaseController extends Controller {
  get user() {
    return this.ctx.session.user;
  }
  success(data) {
    this.ctx.body = { success: true, data };
  }
  notFound(msg) {
    this.ctx.throw(404, msg || "not found");
  }
}
module.exports = BaseController;- 然后让所有的控制器继承这个自定义的 BaseController
js
// app/controller/post.js
const Controller = require("../core/base_controller");
class PostController extends Controller {
  async list() {
    const posts = await this.service.listByUser(this.user);
    this.success(posts);
  }
}静态类 
静态类就是自己封装了方法,通过 require 引入进来
- 在 app/utils新建一个tool.js文件
js
class ResponsedataController {
  static async succss(data = null, message = "success", code = 200) {
    return {
      code,
      message,
      data,
    };
  }
}
module.exports = ResponsedataController;- 在控制器中使用
js
const { Controller } = require("egg");
const Tools = require("../../utils/tool");
class PostController extends Controller {
  async list() {
    // 业务逻辑
    const posts = await this.service.listByUser(this.user);
    this.ctx.body = Tools.success(posts, "success", 200);
  }
}扩展 
egg 框架提供了下面几个扩展点:
- Application: Koa 的全局应用对象(应用级别),全局只有一个,在应用启动时被创建
- Context:Koa 的请求上下文对象(请求级别),每次请求生成一个 Context 实例
- Request:Koa 的 Request 对象(请求级别),提供请求相关的属性和方法
- Response:Koa 的 Response 对象(请求级别),提供响应相关的属性和方法
- Helper:用来提供一些实用的 utility 函数
bash
所有的扩展必须写到app/extend目录下,并且文件名必须以`扩展名.js`结尾,例如:
application.js、context.js、request.js、response.js、helper.jsApplication 扩展 
- 新建 - app/extend/application.js文件
- 扩展有两类:属性扩展和方法扩展 
js
// app/extend/application.js
module.exports = {
  // 方法扩展
  currentTime() {
    return getTime();
  },
  // 属性扩展
  get timeProp() {
    return getTime();
  },
};
function getTime() {
  let now = new Date();
  let year = now.getFullYear();
  let month = now.getMonth() + 1;
  // 月份要是小于10,前面补0
  if (month < 10) {
    month = "0" + month;
  }
  let date = now.getDate();
  //  日期要是小于10,前面补0
  if (date < 10) {
    date = "0" + date;
  }
  let hour = now.getHours();
  // 时间要是小于10,前面补0
  if (hour < 10) {
    hour = "0" + hour;
  }
  let minute = now.getMinutes();
  // 分钟要是小于10,前面补0
  if (minute < 10) {
    minute = "0" + minute;
  }
  let second = now.getSeconds();
  // 秒数要是小于10,前面补0
  if (second < 10) {
    second = "0" + second;
  }
  return `${year}-年${month}月-${date}日 ${hour}:${minute}:${second}`;
}- 在控制器中使用
js
const { Controller } = require("egg");
class ExtendController extends Controller {
  async applicationindex() {
    const { ctx, app } = this;
    const method_result = app.currentTime();
    const attr = app.timeProp;
    ctx.body = {
      code: 200,
      data: {
        time: method_result,
        time2: attr,
      },
    };
  }
}
module.exports = ExtendController;Context 扩展 
- 新建 - app/extend/context.js文件
- 扩展有两类:属性扩展和方法扩展 
js
// app/extend/context.js
module.exports = {
  params(key) {
    const method = this.request.method;
    if (method === "GET") {
      return key ? this.query[key] : this.query;
    } else {
      return key ? this.request.body[key] : this.request.body;
    }
  },
};- 在控制器中使用
js
const { Controller } = require("egg");
class ExtendController extends Controller {
  async contextindex() {
    const { ctx } = this;
    const params = ctx.params("id");
    console.log(params);
    ctx.body = params;
  }
}
module.exports = ExtendController;- 路由
js
module.exports = (app) => {
  const { router, controller } = app;
  // router
  const middleRouter = router.namespace("/extend");
  middleRouter.get("/application", controller.extend.extend.applicationindex);
  middleRouter.get("/context", controller.extend.extend.contextindex);
};- 使用
bash
http://127.0.0.1:7001/extend/context?id=5Helper 扩展 
- 新建 - app/extend/helper.js文件
- 扩展有两类:属性扩展和方法扩展 
js
// app/extend/helper.js
module.exports = {
  base64Encode(str = "") {
    return Buffer.from(str).toString("base64");
  },
};- 在控制器中使用
js
const { Controller } = require("egg");
class ExtendController extends Controller {
  async helperindex() {
    const { ctx } = this;
    const testbase64 = ctx.helper.base64Encode("hello world");
    ctx.body = testbase64;
  }
}
module.exports = ExtendController;- 路由
js
module.exports = (app) => {
  const { router, controller } = app;
  // router
  const middleRouter = router.namespace("/extend");
  middleRouter.get("/application", controller.extend.extend.applicationindex);
  middleRouter.get("/context", controller.extend.extend.contextindex);
  middleRouter.get("/helper", controller.extend.extend.helperindex);
};- 使用
bash
http://127.0.0.1:7001/extend/helperrequest 扩展 
- 新建 - app/extend/request.js文件
- 扩展有两类:属性扩展和方法扩展 
js
// app/extend/request.js
module.exports = {
  get token() {
    return this.get("token");
  },
};- 在控制器中使用
js
const { Controller } = require("egg");
class ExtendController extends Controller {
  async requestindex() {
    const { ctx } = this;
    const token = ctx.request.token;
    ctx.body = {
      status: 200,
      body: {
        token,
      },
    };
  }
}
module.exports = ExtendController;- 路由
js
module.exports = (app) => {
  const { router, controller } = app;
  // router
  const middleRouter = router.namespace("/extend");
  middleRouter.get("/application", controller.extend.extend.applicationindex);
  middleRouter.get("/context", controller.extend.extend.contextindex);
  middleRouter.get("/helper", controller.extend.extend.helperindex);
  middleRouter.get("/request", controller.extend.extend.requestindex);
};- 使用
bash
请求头部带token
http://127.0.0.1:7001/extend/requestresponse 扩展 
- 新建 - app/extend/response.js文件
- 扩展有两类:属性扩展和方法扩展 
js
// app/extend/request.js
module.exports = {
  set token(token) {
    return this.set("token", token);
  },
};- 在控制器中使用
js
const { Controller } = require("egg");
class ExtendController extends Controller {
  async responseindex() {
    const { ctx } = this;
    ctx.response.token = "ceshitoken";
    ctx.body = "newResponse";
  }
}
module.exports = ExtendController;- 路由
js
module.exports = (app) => {
  const { router, controller } = app;
  // router
  const middleRouter = router.namespace("/extend");
  middleRouter.get("/application", controller.extend.extend.applicationindex);
  middleRouter.get("/context", controller.extend.extend.contextindex);
  middleRouter.get("/helper", controller.extend.extend.helperindex);
  middleRouter.get("/request", controller.extend.extend.requestindex);
  middleRouter.get("/response", controller.extend.extend.responseindex);
};- 使用
bash
返回数据的头部里面就有token了
http://127.0.0.1:7001/extend/response