9.Koa基本使用

1,114 阅读5分钟

简介

Koa 是一个新的 web 框架,由 Express 幕后的原班人马打造, 致力于成为 web 应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石。 通过利用 async 函数,Koa 帮你丢弃回调函数,并有力地增强错误处理。 Koa 并没有捆绑任何中间件, 而是提供了一套优雅的方法,帮助您快速而愉快地编写服务端应用程序。

安装

npm i koa -S

使用

//引入
const Koa = require('koa');
//实例化
const app = new Koa();
//中间件
app.use(async ctx => {
    ctx.body = 'hello world';
});
//监听
app.listen(3000, () => {
    console.log('listen on 3000 port!');
})

中间件

中间件就是一个异步函数,主要对请求和响应进行预处理; 当一个中间件调用 next() 则该函数暂停并将控制传递给定义的下一个中间件。

在调用next()方法的前面对请求做处理,在调用next()方法的后面对响应做处理

Middleware更多信息

中间件机制

通过Koa实例调用use方法加载中间件时,会有一个数组来存储,use的调用顺序会决定中间件的执行顺序。每一个中间件都是一个函数,接收两个参数,第一个是ctx上下文对象,第二个是next函数。当向服务器发起请求获取响应时,会先从存储中间件的数组中取第一个函数开始执行,当碰到中间件函数中调用next()方法时,会在此处暂停等待,并跳到下一个中间件函数执行。每一个中间件函数执行完毕后都会返回一个promise对象。

洋葱模型:

示列

发起请求时获取start,响应时获取当前时间-start,从而得到响应时长。

const Koa = require('koa');
const app = new Koa();

// logger
app.use(async (ctx, next) => {
    await next(); //相当于一个分割线
    const rt = ctx.response.get('X-Response-Time');
    console.log(`${ctx.method} ${ctx.url} - ${rt}`);
});

// x-response-time
app.use(async (ctx, next) => {
    const start = Date.now();
    await next();
    const ms = Date.now() - start;
    ctx.set('X-Response-Time', `${ms}ms`);
});

// response
app.use(async ctx => {
    ctx.status = 200; //设置响应状态码
    ctx.type = 'html'; //等价于 ctx.set('Content-Type', 'text/html');
    ctx.body = 'Hello World'; //设置响应体
});

app.listen(3000);

错误处理

手动处理

运行到模拟错误的中间件函数时,抛出错误,跳转到错误处理中间件函数,在这里返回给前端信息,并触发app上绑定的error函数在后台显示错误信息。

const Koa = require('koa');
const app = new Koa();

//错误处理中间件,需要写在其他中间件的最上面
app.use(async (ctx, next) => {
    try {
        await next();
    } catch (error) {
        //显示状态码
        ctx.status = error.status || 500;
        console.log(ctx.status);
        //设置返回给前端的内容类型
        ctx.type = 'json';
        ctx.body = {
            ok: 0,
            message: error.message
        };

        //触发错误处理函数,显示后端打印
        ctx.app.emit('error', error, ctx);
    }
})

//模拟一个错误,抛出异常 ctx.throw(),需要在响应之前
app.use(async ctx => {
    ctx.throw(401, '发生错误');
    /* 等价于:
        const err = new Error('name required');
        err.status = 400;
        err.expose = true;//为 true 时,适用于客户端,默认为 false
        //请注意,这些是用户级错误,并用 err.expose 标记,这意味着消息适用于客户端响应,
        //这通常不是错误消息的内容,因为您不想泄漏故障详细信息。
        throw err;
    */
})

//响应
app.use(async ctx => {
    /* const a = 1;
    a = 2; */
    ctx.body = 'hello world';
})

//全局错误处理
app.on('error', (err, ctx) => {
    console.log('错误处理', err.message); //错误处理 Assignment to constant variable.
});

app.listen(3000, () => {
    console.log('listen on 3000 port!');
})

使用koa-onerror中间件

安装

npm i koa-onerror -S 使用

导入后直接调用onerror()即可,不需要自己再去写处理错误中间件函数中的更多的内容。

const fs = require('fs');
const koa = require('koa');
const app = new koa();
//导入
const onerror = require('koa-onerror');

//调用
onerror(app);

//处理错误的中间件
app.use(async (ctx, next) => {
    try {
        await next();
    } catch (error) {
        ctx.body = fs.createReadStream('not exist');
    }
})

//模拟一个错误,抛出异常 ctx.throw(),需要在响应之前
app.use(async ctx => {
    ctx.throw(401, '发生错误');
})

app.use(async ctx => {
    ctx.body = 'hello world';
});

//全局错误处理
app.on('error', (err, ctx) => {
    console.log('错误处理', err.message); //错误处理 Assignment to constant variable.
});

app.listen(3000, () => {
    console.log('listen on 3000 port!');
})

日志处理

使用koa-logger中间件

安装

npm i koa-logger -S 使用

导入后直接通过app.use(logger())使用即可。

const koa = require('koa');
const app = new koa();
//导入
const logger = require('koa-logger')

//使用
app.use(logger())

app.use(async ctx => {
    ctx.body = 'hello world';
});

app.listen(3000, () => {
    console.log('listen on 3000 port!');
})

路由处理

使用koa-router中间件

安装

npm i koa-router -S 使用

创建router文件夹,并在文件夹下创建index.jsuser.js.

Tips

  • 通过ctx.state命名空间实现在所有路由中共享数据,但是需要写在入口的 js 文件中,且要在注册路由之前
  • 对于get请求可以直接通过ctx.params.idctx.query等获取id和查询参数
  • 对于post请求需要先安装bodyparser中间件,才能解析获取请求体中的数据ctx.request.body

index.js

const Router = require('koa-router');
const router = new Router();
//路由中间件,处理请求,定义api接口

router.get('/', (ctx, next) => {
    //获取共享数据
    console.log(ctx.state.navList);
    ctx.body = 'hello world';
})

router.get('/login', (ctx, next) => {
    ctx.redirect('./sign');
})

router.get('/sign', (ctx, next) => {
    //获取共享数据
    console.log(ctx.state.navList);
    ctx.body = '注册页面';
})

router.post('/', ctx => {
    //处理post请求,请求体参数的问题
    //需要下载中间件 cnpm i koa-bodyparser -S
    console.log(ctx.request.body);
    ctx.body = {
        ok: 1
    };
})

module.exports = router;

user.js

const Router = require('koa-router');
const router = new Router();

//添加前缀
router.prefix('/user'); //等价于 const router = new Router({prefix:'/user'});

// http://localhost:3000/user?name=holo&age=20
router.get('/', (ctx, next) => {
    //获取查询参数
    console.log(ctx.query);
    ctx.body = '用户界面';
})

router.get('/:id', (ctx, next) => {
    //获取 id
    //两种方式都能获取到 id
    // console.log(ctx.request.params.id);
    // console.log(ctx.params.id);
    ctx.body = 'params 用法';
})

router.get('/:id/:pid', (ctx, next) => {
    ctx.body = `用户界面/${ctx.params.id}/${ctx.params.pid}`;
})

module.exports = router;

导入,使用

const koa = require('koa');
const app = new koa();
//导入处理 post 请求的中间件
const bodyParser = require('koa-bodyparser');
//导入路由
const routerIndex = require('./router/index');
const userIndex = require('./router/user');

//命名空间,写在入口的 js 文件中,且要在注册路由之前
app.use(async (ctx, next) => {
    //通过 state 共享数据,在所有的路由中都能够访问到
    ctx.state.navList = {
        a: 1
    }
    //从数据库中获取模型对象 find() 查找对应的数据,通过state共享数据
    await next();
})

//使用 bodyparser 中间件
app.use(bodyParser());
//注册路由
app.use(routerIndex.routes());
app.use(routerIndex.allowedMethods());
//用户路由
app.use(userIndex.routes());
app.use(userIndex.allowedMethods());

app.listen(3000, () => {
    console.log('listen on 3000 port!');
})

设置静态资源目录

使用koa-static中间件

安装

npm i koa-static -S 使用

//处理静态资源目录
const koaStatic = require('koa-static');

//设置静态资源服务器目录,注意写在路由的前面
app.use(koaStatic(__dirname + 'public'));