简介
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()方法的后面对响应做处理。
中间件机制
通过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.js和user.js.
Tips:
- 通过
ctx.state命名空间实现在所有路由中共享数据,但是需要写在入口的 js 文件中,且要在注册路由之前 - 对于get请求可以直接通过
ctx.params.id、ctx.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'));