Web应用开发框架-egg(三)05-基础功能——控制器之controller介绍与设计技巧、csrf防范与重定向 & service服务的使用场景

Web应用开发框架-egg(三)05-基础功能——控制器之controller介绍与设计技巧、csrf防范与重定向 & service服务的使用场景

控制器

简单的说 Controller 负责解析用户的输入,处理后返回相应的结果

作用
  • RESTful 接口中,Controller 接受用户的参数,从数据库中查找内容返回给用户或者将用户的请求更新到数据库中。
    • 返回json
  • 在 HTML 页面请求中,Controller 根据用户访问不同的 URL,渲染不同的模板得到 HTML 返回给用户。
  • 在代理服务器中,Controller 将用户的请求转发到其他服务器上,并将其他服务器的处理结果返回给用户。
    • 调用第三方的接口
推荐用法(适合在controller中完成的逻辑)
  1. 获取用户通过 HTTP 传递过来的请求参数。(解析参数)
  2. 校验、组装参数。(校验)
  3. 调用 Service 进行业务处理,必要时处理转换 Service 的返回结果,让它适应用户的需求。(数据库查询)
  4. 通过 HTTP 将结果响应给用户。(返回response)
如何编写controller
'use strict';
// import HttpController from './base/http';
const Controller = require('egg').Controller;

class HomeController extends Controller {
    
    
  async index() {
    
    
    const {
    
     ctx } = this;
    ctx.body = await this.service.user.find() // ctx 来自koa
  }

  // 1. 需要在 controller定义怎么渲染
  async hello() {
    
    
    const {
    
     ctx } = this;
    await ctx.render('hello.nj'); // 自动的读取view/hello.nj
  }

  async addUser() {
    
    
    const {
    
     ctx } = this;
    console.log(ctx.request.body);
    console.log(ctx.csrf)
    ctx.body = 'success';
  }

  async redirect() {
    
    
    const {
    
     ctx } = this;
    ctx.redirect('https://taobao.com');
  }
}

module.exports = HomeController;

router调用

// app/router.js
module.exports = app => {
    
    
  const {
    
     router, controller } = app;
  router.post('/api/posts', controller.post.create);
}

Controller 支持多级目录,例如如果我们将上面的 Controller 代码放到 app/controller/sub/post.js 中,则可以在 router 中这样使用:

// app/router.js
module.exports = app => {
    
    
  app.router.post('/api/posts', app.controller.sub.post.create);
}
Controller的属性

项目中的 Controller 类继承于 egg.Controller,会有下面几个属性挂在 this 上。

  • this.ctx: 当前请求的上下文 Context 对象的实例,通过它我们可以拿到框架封装好的处理当前请求的各种便捷属性和方法。
  • this.app: 当前应用 Application 对象的实例,通过它我们可以拿到框架提供的全局对象和方法。
  • this.service:应用定义的 Service,通过它我们可以访问到抽象出的业务层,等价于 this.ctx.service
  • this.config:应用运行时的配置项
  • this.logger:logger 对象,上面有四个方法(debuginfowarnerror),分别代表打印四个不同级别的日志,使用方法和效果与 context logger 中介绍的一样,但是通过这个 logger 对象记录的日志,在日志前面会加上打印该日志的文件路径,以便快速定位日志打印位置。
自定义Controller基类

按照类的方式编写 Controller,不仅可以让我们更好的对 Controller 层代码进行抽象(例如将一些统一的处理抽象成一些私有方法),还可以通过自定义 Controller 基类的方式封装应用中常用的方法。

// app/controller/base/http.js

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

class HttpController extends Controller {
    
    
  success(data) {
    
    
    this.ctx.body = {
    
    
        msg: 'success',
        code: 0,
        data
    }
  }
}

module.exports = HttpController;

//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);
  }
}
获取request参数
  • query 地址栏参数, 会丢弃重复的参数
  • params route参数
  • queries 地址栏参数,不会丢弃重复的参数
  • request.body的参数 框架内置了 bodyParser 中间件来对这两类格式的请求 body 解析成 object 挂载到 ctx.request.body

一个常见的错误是把 ctx.request.body 和 ctx.body 混淆,后者其实是 ctx.response.body 的简写。**

csrf防范

egg会默认带上csrf防护,不加上token是取不到post中的参数的。

  • 从ctx.csrf中读取token
  • 通过header的x-csrf-token字段携带过来
重定向

框架通过 security 插件覆盖了 koa 原生的 ctx.redirect 实现,以提供更加安全的重定向。

  • ctx.redirect(url) 如果不在配置的白名单域名内,则禁止跳转。
  • ctx.unsafeRedirect(url) 不判断域名,直接跳转,一般不建议使用,明确了解可能带来的风险后使用。
// config/config.default.js
exports.security = {
    
    
  domainWhiteList:['.domain.com'],  // 安全白名单,以 . 开头
};
服务(Service)

简单来说,Service 就是专门请求和组装数据的。

使用 场景
  • 复杂数据的处理,比如要展现的信息需要从数据库获取,还要经过一定的规则计算,才能返回用户显示。或者计算完成后,更新到数据库。
  • 第三方服务的调用,比如 GitHub 信息获取等。
// app/service/user
const Service = require('egg').Service;

class UserService extends Service {
    
    
    async find(uid) {
    
    
        return [1, 2, 3, 4];
    }
}

module.exports = UserService;
'use strict';
// import HttpController from './base/http';
const Controller = require('egg').Controller;

class HomeController extends Controller {
    
    
  async index() {
    
    
    const {
    
     ctx } = this;
    ctx.body = await this.service.user.find() // ctx 来自koa
  }
}

module.exports = HomeController;

猜你喜欢

转载自blog.csdn.net/weixin_44867717/article/details/134130660