Nodejs

Section-4 Koa 框架的控制器以及设计更合理的目录结构

2019-07-13  本文已影响0人  羽晞yose

Lesson-1 控制器简介

什么是控制器

为什么要控制器?

获取 HTTP 请求参数

发送 HTTP 响应

编写控制器最佳实践


Lesson-2 获取 HTTP 请求参数

操作步骤

调试使用的是vscode,点击F5,进入调试(这里注意一下,不要自己在其他地方执行npm start,也不需要自己来执行这个命令行启动服务器,当进入调试的时候,将会自动启动服务器,否则会出现冲突报错)


在git里先启动了服务,调试的时候会报错
进入正常调试的vscode界面
获取 query

也就是获取请求中 ? 后面的参数
请求地址为 localhost:3000/user/master?query=彩蛋,获取代码为 ctx.query

获取 router params

这个前面一直出现,也就是获取路径后的参数
请求地址为 localhost:3000/user/master?query=彩蛋,获取代码为 ctx.params

query 和 params 断点调试结果
获取 body

获取请求体,一般我们常用格式为json。这里需要安装一个 koa-bodyparser 插件,否则获取不到。不过后续使用的时候其实会有问题,参考文章 koa2 使用 koa-body 代替 koa-bodyparser 和 koa-multer,不过为了不增加目前难度,就还是使用的koa-bodyparser。顺便说一下,全局引用中间件,就是app.use(中间件),否则就是路由级引用,也就是router.use('路由地址', 中间件)

执行npm i koa-bodyparser -S

// index.js
const bodyparser = require('koa-bodyparser');
app.use(bodyparser());

请求地址为 localhost:3000/user,请求方法为 POST ,获取代码为 ctx.request.body

postman切换到body,选择raw,并写入请求体
image.png
获取 header

获取请求头,依旧使用刚才获取请求体的内容,这样能看到请求的content-type
请求地址为 localhost:3000/user,请求方法为 POST ,获取代码为 ctx.request.header

获取请求头

Lesson-3 发送 HTTP 响应

操作步骤

之前已经使用过的,我这里就不再重复上代码了,简单带过去

发送status

设置body.status = 204,就是设置响应为204状态码

发送body

设置ctx.body = '这是设置body',就是设置响应body,内容为'这是设置body'

发动 header

使用ctx.set方法,以之前的代码为例,让人家知道,user除了有GET方法,还有POST方法

// 获取用户列表
userRouter.get('/', (ctx) => {
    ctx.set('Allow', 'GET, POST'); // 设置请求头
    ctx.body = [
        {name: '韩梅梅'},
        {name: '李蕾'}
    ];
});
设置响应头

实现用户的增删改查

这里我就不放 postman 验证截图了,只上代码,后面会加上 mongoDB,不过现在还没有,所以先使用的内存数据库(其实就是变量)

const Koa = require('koa');
const bodyparser = require('koa-bodyparser');
const Router = require('koa-router');
const app = new Koa();
const userRouter = new Router({prefix: '/user'});

// 内存数据库
const db = [{name: '李雷'}];

// 获取用户列表
userRouter.get('/', (ctx) => {
    ctx.body = db;
});

// 增加用户
userRouter.post('/', (ctx) => {
    db.push(ctx.request.body);
    ctx.body = ctx.request.body;
});

// 获取特定用户
userRouter.get('/:id', (ctx) => {
    ctx.body = db[+ctx.params.id];
});

// 修改特定用户
userRouter.put('/:id', (ctx) => {
    db[+ctx.params.id] = ctx.request.body;
    ctx.body = ctx.request.body;
});

// 删除用户
userRouter.delete('/:id', (ctx) => {
    db.splice(+ctx.params.id, 1);
    ctx.status = 204; // 没有内容,但是成功了
});

app.use(bodyparser());
app.use(userRouter.routes());
app.use(userRouter.allowedMethods());


app.listen(3000, () => {
    console.log(`start server...`);
});

Lesson-4 更合理的目录结构

操作步骤

重构文件目录

现在的想法是这样,创建app目录,原本根目录下的index.js文件移动到app里面去,作为总入口文件
创建routes文件夹,里面用于存放所有页面的路由,并导出
创建controllers文件夹,里面用于存放对应页面的控制器(控制器其实就是中间件,也就是方法),并使用类 + 类方法导出的形式来进行维护

文件目录现在变为这样
|- 根目录
  |- app
    |- routes
      |- home.js -- 主页路由
      |- users.js -- 用户列表页路由
      |- index.js -- 批量读取文件,并批量注册到app上
    |- controllers
      |- home.js -- 主页控制器
      |- users.js -- 用户列表页控制器
  |- node_modules
  |- LICENSE
  |- package-lock.json
  |- package.json
  |- README.md

使用类 + 类方法的形式导出中间件

现在将用户列表页相关的中间件全部提取出来,创建一个 UserCtl 类,里面有所有增删改查的方法,主页也一样,不重复展示代码

// 内存数据库,测试使用
const db = [{name: '李雷'}];

class UsersCtl {
    find (ctx) {
        ctx.body = db;
    }

    findId (ctx) {
        ctx.body = db[+ctx.params.id];
    }

    create (ctx) {
        db.push(ctx.request.body);
        ctx.body = ctx.request.body;
    }

    update (ctx) {
        db[+ctx.params.id] = ctx.request.body;
        ctx.body = ctx.request.body;
    }

    delete (ctx) {
        db.splice(+ctx.params.id, 1);
        ctx.status = 204; // 没有内容,但是成功了
    }
}

module.exports = new UsersCtl();

重构主页路由

其实就是原本user所对应的所有方法,现在是使用ES Module来获取对应的方法
const { find, findId, create, update, delete: del } = require('../controllers/users');
随便以router.get('/', find);为例,这里 find 不能写成 find(ctx),因为后者的写法是立即执行,而我们是需要路由匹配到了才能获取到ctx上下文环境,因此这里只是相当于注入一个方法,这个方法会接受两个参数 ctx 和 next,不过这里暂时没用到 next 就没写

const Router = require('koa-router');
const router = new Router({prefix: '/user'});
const { find, findId, create, update, delete: del } = require('../controllers/users');

// 获取用户列表
router.get('/', find);

// 增加用户
router.post('/', findId);

// 获取特定用户
router.get('/:id', create);

// 修改特定用户
router.put('/:id', update);

// 删除用户
router.delete('/:id', del);

module.exports = router;

实现批量注册路由,启动并完善请求头

实现的思路是遍历routes文件夹下的所有文件(因为该文件下只存放router),因此创建一个index.js文件,使用nodejs自带的rs模块遍历所有的文件名,将其注册启动等

// node自带模块,用于读取文件
const fs = require('fs');

module.exports = app => {
    // 返回一个包含指定目录下所有文件名称的数组对象,会把当前文件也读取进去
    fs.readdirSync(__dirname).forEach(file => {
        if(file === 'index.js') return; // 如果是index.js页面就返回,也就是当前文件,不是路由不能进行注册

        const route = require(`./${file}`);
        app.use(route.routes()).use(route.allowedMethods());
    });
}

重构后的总入口文件

const Koa = require('koa');
const bodyparser = require('koa-bodyparser');
const app = new Koa(); // 实例化koa
const routes = require('./routes');

// 启动路由
app.use(bodyparser());
routes(app);

app.listen(3000, () => {
    console.log(`start server...`);
});
上一篇下一篇

猜你喜欢

热点阅读