美文网首页Nodejs
Section-4 Koa 框架的控制器以及设计更合理的目录结构

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

作者: 羽晞yose | 来源:发表于2019-07-13 23:30 被阅读0次

    Lesson-1 控制器简介

    什么是控制器

    • 拿到路由分配的任务,并执行
    • 在Koa中,是一个中间件

    为什么要控制器?

    • 获取 HTTP 请求参数
    • 处理业务逻辑
    • 发送 HTTP 响应

    获取 HTTP 请求参数

    • Query String,如?q=keyword,是可选项
    • Router Params,如/user/:id,是必选项
    • Body,如{name: "李雷"},请求体,一般为json
    • Header,如Accept、Cookie

    发送 HTTP 响应

    • 发送 Status,如 200/400 等
    • 发动 Body,如{name: "李雷"}
    • 发送 Header,如 Allow、 Content-type

    编写控制器最佳实践

    • 每个资源的控制器放在不同的文件里
    • 尽量使用类+类方法的形式编写控制器
    • 严谨的错误处理

    Lesson-2 获取 HTTP 请求参数

    操作步骤

    • 学习断点调试
    • 获取 query
    • 获取 router params
    • 获取 body
    • 获取 header

    调试使用的是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
    • 发送 header
    • 实现用户的增删改查

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

    发送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...`);
    });
    

    相关文章

      网友评论

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

        本文链接:https://www.haomeiwen.com/subject/gcevkctx.html