koa

作者: 欢欣的膜笛 | 来源:发表于2020-06-17 21:32 被阅读0次

    Koa是一个基于nodejs的入门级http服务。 通过利用async函数,更简单化、流程化、模块化的方式实现回调部分。

    • 创建koa2工程
    // 导入koa,和koa 1.x不同,在koa2中,我们导入的是一个class,因此用大写的Koa表示:
    const Koa = require('koa');
    
    // 创建一个Koa对象表示web app本身:
    const app = new Koa();
    
    // 对于任何请求,app将调用该异步函数处理请求:
    app.use(async (ctx, next) => {
        await next();
        ctx.response.type = 'text/html';
        ctx.response.body = '<h1>Hello, koa2!</h1>';
    });
    
    // 在端口3000监听:
    app.listen(3000);
    console.log('app started at port 3000...');
    

    说明:
    1. 参数ctx是由koa传入的封装了requestresponse的变量,nextkoa传入的将要处理的下一个异步函数。
    2. ctx对象有一些简写的方法,例如ctx.url相当于ctx.request.urlctx.type相当于ctx.response.type
    3. 由async标记的函数称为异步函数,在异步函数中,可以用await调用另一个异步函数。
    4. koa把很多async函数组成一个处理链,每个async函数都可以做一些自己的事情,然后用await next()来调用下一个async函数。我们把每个async函数称为middleware,这些middleware可以组合起来,完成很多有用的功能。

    • koa middleware
    app.use(async (ctx, next) => {
        console.log(`${ctx.request.method} ${ctx.request.url}`); // 打印URL
        await next(); // 调用下一个middleware
    });
    
    app.use(async (ctx, next) => {
        const start = new Date().getTime(); // 当前时间
        await next(); // 调用下一个middleware
        const ms = new Date().getTime() - start; // 耗费时间
        console.log(`Time: ${ms}ms`); // 打印耗费时间
    });
    
    app.use(async (ctx, next) => {
        await next();
        ctx.response.type = 'text/html';
        ctx.response.body = '<h1>Hello, koa2!</h1>';
    });
    

    说明:
    1. 调用app.use()的顺序决定了middleware的顺序
    2. 如果一个middleware没有调用await next(),后续的middleware将不再执行了,如检测权限时,ctx.response.status = 403

    • koa-router
    1. router.get('/path', async fn):处理get请求
    const Koa = require('koa');
    const app = new Koa();
    const router = require('koa-router')();
    
    app.use(async (ctx, next) => {
        console.log(`Process ${ctx.method} ${ctx.url}...`);
        await next();
    });
    
    router.get('/hello/:name', async (ctx, next) => {
        let name = ctx.params.name;
        ctx.response.body = `<h1>Hello, ${name}!</h1>`;
    });
    
    router.get('/', async (ctx, next) => {
        ctx.response.body = '<h1>Index</h1>';
    });
    
    app.use(router.routes());
    
    app.listen(3000, () => console.log('app started at port 3000...'));
    
    1. router.post('/path', async fn) :处理post请求
      post请求通常会发送一个表单,或者JSON,它作为requestbody发送,需要引入koa-bodyparser来解析原始request请求,然后,把解析后的参数,绑定到ctx.request.body中。
    const Koa = require('koa');
    const app = new Koa();
    const router = require('koa-router')();
    
    router.get('/', async (ctx, next) => {
        ctx.response.body = `<h1>Index</h1>
            <form action="/signin" method="post">
                <p>Name: <input name="name" value="koa"></p>
                <p>Password: <input name="password" type="password"></p>
                <p><input type="submit" value="Submit"></p>
            </form>`;
    });
    
    router.post('/signin', async (ctx, next) => {
        let name = ctx.request.body.name || '';
        let password = ctx.request.body.password || '';
        console.log(`signin with name: ${name}, password: ${password}`);
        if (name === 'koa' && password === '12345') {
            ctx.response.body = `<h1>Welcome, ${name}!</h1>`;
        } else {
            ctx.response.body = `<h1>Login failed!</h1>
            <p><a href="/">Try again</a></p>`;
        }
    });
    
    // koa-bodyparser必须在router之前被注册到app对象上
    const bodyParser = require('koa-bodyparser');
    app.use(bodyParser());
    
    app.use(router.routes());
    
    app.listen(3000, () => console.log('app started at port 3000...'));
    
    • 封装处理不同的URL
    url-koa/
    |
    +- controllers/
    |  |
    |  +- login.js <-- 处理login相关URL
    |  |
    |  +- users.js <-- 处理用户管理相关URL
    |
    +- app.js <-- 使用koa的js
    |
    +- package.json <-- 项目描述文件
    |
    +- node_modules/ <-- npm安装的所有依赖包
    
    // app.js
    const Koa = require('koa');
    // 引入koa-bodyparser来解析原始request请求,然后,把解析后的参数,绑定到ctx.request.body中
    const bodyParser = require('koa-bodyparser');
    // 导入controller middleware:
    const controller = require('./controller');
    
    const app = new Koa();
    
    app.use(bodyParser())
        .use(controller())
        .listen(3000, () => console.log('app started at port 3000...'));
    
    // controller.js:扫描controllers目录和创建router的代码,作为一个简单的middleware使用
    const fs = require('fs');
    
    const addMapping = (router, mapping) => {
        for (let url in mapping) {
            if (url.startsWith('GET ')) {
                // 如果url类似"GET xxx"
                let path = url.substring(4);
                router.get(path, mapping[url]);
                console.log(`register URL mapping: GET ${path}`);
            } else if (url.startsWith('POST ')) {
                // 如果url类似"POST xxx"
                let path = url.substring(5);
                router.post(path, mapping[url]);
                console.log(`register URL mapping: POST ${path}`);
            } else {
                // 无效的URL
                console.log(`invalid URL: ${url}`);
            }
        }
    }
    
    const addControllers = (router, dir) => {
        // 这里可以用sync是因为启动时只运行一次,不存在性能问题
        let files = fs.readdirSync(__dirname + '/' + dir);
        // 过滤出.js文件
        let js_files = files.filter((f) => {
            return f.endsWith('.js');
        });
    
        // 处理每个js文件
        for (let f of js_files) {
            console.log(`process controller: ${f}...`);
            // 导入js文件
            let mapping = require(__dirname + '/' + dir + '/' + f);
            addMapping(router, mapping);
        }
    }
    
    module.exports = function (dir) {
        let controllers_dir = dir || 'controllers'; // 如果不传参数,扫描目录默认为'controllers'
        let router = require('koa-router')();
        addControllers(router, controllers_dir);
        return router.routes();
    };
    
    // login.js
    
    const fn_index = async (ctx, next) => {
        ctx.response.body = `<h1>Index</h1>
            <form action="/signin" method="post">
                <p>Name: <input name="name" value="koa"></p>
                <p>Password: <input name="password" type="password"></p>
                <p><input type="submit" value="Submit"></p>
            </form>`;
    };
    
    const fn_signin = async (ctx, next) => {
        let name = ctx.request.body.name || '';
        let password = ctx.request.body.password || '';
        console.log(`signin with name: ${name}, password: ${password}`);
        if (name === 'koa' && password === '12345') {
            ctx.response.body = `<h1>Welcome, ${name}!</h1>`;
        } else {
            ctx.response.body = `<h1>Login failed!</h1>
            <p><a href="/">Try again</a></p>`;
        }
    };
    
    
    module.exports = {
        'GET /': fn_index,
        'POST /signin': fn_signin
    };
    
    // hello.js
    const fs = require('fs');
    
    const fn_hello = async (ctx, next) => {
        let name = ctx.params.name;
        ctx.response.body = `<h1>Hello, ${name}!</h1>`;
    };
    
    module.exports = {
        'GET /hello/:name': fn_hello
    };
    
    • context
      koa为了能够简化API,引入上下文context概念,将原始请求对象req和响应对象res封装并挂载到context上,并且在context上设置gettersetter,从而简化操作。

    • 中间件
      Koa中间件机制就是函数组合的概念,将一组需要顺序执行的函数复合为一个函数,外层函数的参数实际是内层函数的返回值。洋葱圈模型。

    相关文章

      网友评论

          本文标题:koa

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