Koa.js 2.x 学习笔记
记录笔者日常学习笔记,无深解内容,除了笔者无人看懂。
Koa.js
Koa-router 学习笔记
简介
koa 是由 Express 原班人马打造的,致力于成为一个更小、更富有表现力、更健壮的 Web 框架。使用 koa 编写 web 应用,通过组合不同的 generator,可以免除重复繁琐的回调函数嵌套,并极大地提升错误处理的效率。koa 不在内核方法中绑定任何中间件,它仅仅提供了一个轻量优雅的函数库,使得编写 Web 应用变得得心应手。
安装
Koa需要 node v7.6.0或更高版本来支持ES2015、异步方法
新建一个测试目录,然后执行 npm init
生成package.json
配置文件。
执行koa安装
npm i koa
新建一个app.js
文件
const Koa = require('koa');
const app = new Koa();
app.use(async ctx => {
ctx.body = 'Hello World';
});
app.listen(3000);
执行node命令,运行项目
node my-koa-app.js
访问http://localhost:3000/
就可以看到Hello World
了
中间件
通俗的讲:中间件就是匹配路由之前或者匹配路由完成做的一系列的操作,我们就可以把它叫做中间件。
在express 中间件(Middleware) 是一个函数,它可以访问请求对象(request object(req)),响应对象(response object()res),和web应用中处理请求-相应循环流程中的中间件,一般被命名为next的变量。在Koa中中间件和express有点类似。
中间件的功能包括:
- 执行任何代码
- 修改请求和响应请求对象
- 终结请求-响应循环
- 调用堆栈中的下一个中间件
如果get、post回调函数中,没有next参数,那么就匹配上第一个路由,就不会往下匹配了。如果想往下匹配的话,那么就需要写next()。
Koa应用可以使用如下几种中间件:
- 应用级中间件
- 路邮级中间件
- 错误处理中间件
- 第三方中间件
可以写两个参数,第一个是匹配的路径,第二个是回调函数,第一个参数可以省略
app.use('/',function(){});
不管app.use
和router
的书写顺序如何,都是先执行app.use
再执行router
应用级中间件
// 引入Koa模块
const Koa = require('koa');
// 引入Koa-router
const Router = require('koa-router');
// 实例化Koa模块
const app = new Koa();
// 实例化路由模块
const router = new Router();
// Koa 中间件
// app.use('/',function(){}); //可以写两个参数,第一个是匹配的路径,第二个是回调函数,第一个参数可以省略
// 匹配任何路由,如果不写next,这个路由被匹配到了就不会继续向下匹配了
// app.use(async (ctx)=>{
// ctx.body = '这是一个中间件';
// });
// 应用级中间件
// 匹配任何路由之前打印日期
app.use(async (ctx,next)=>{
console.log(new Date());
await next(); //当前路由匹配完成以后继续向下匹配
});
// 配置路由
// ctx 上下文 context, 包含了request和response等信息
router.get('/',async (ctx)=>{
ctx.body = '网站首页'; //返回数据 相当于:原生里面的res.writeHead() res.end()
}).get('/news',async (ctx)=>{
ctx.body = '新闻列表页面';
}).get('/login',async (ctx)=>{
ctx.body = '网站登录页面';
});
// 启动路由
app
.use(router.routes()) /*启动路由*/
.use(router.allowedMethods()); //作用:当请求出错时处理逻辑
/*
* router.allowedMethods()作用: 这是官方文档的推荐用法,我们可以
* 看到 router.allowedMethods()用在了路由匹配 router.routes()之后,所以在当所有
* 路由中间件最后调用.此时根据 ctx.status 设置 response 响应头
*
*/
// 监听3000端口
app.listen(3000,()=>{
console.log('starting at port 3000');
});
路由级中间件
// 引入Koa模块
const Koa = require('koa');
// 引入Koa-router
const Router = require('koa-router');
// 实例化Koa模块
const app = new Koa();
// 实例化路由模块
const router = new Router();
// Koa 中间件
// app.use('/',function(){}); //可以写两个参数,第一个是匹配的路径,第二个是回调函数,第一个参数可以省略
// 匹配任何路由之前打印日期
app.use(async (ctx,next)=>{
console.log(new Date());
await next(); //当前路由匹配完成以后继续向下匹配
});
// 配置路由
// ctx 上下文 context, 包含了request和response等信息
router.get('/',async (ctx)=>{
ctx.body = '网站首页'; //返回数据 相当于:原生里面的res.writeHead() res.end()
});
// 路由级中间件
// 匹配带news路由以后继续向下匹配路由
router.get('/news',async (ctx,next)=>{
console.log('这是一个新闻路由');
await next();
});
router.get('/news',async (ctx)=>{
ctx.body = '新闻列表页面';
});
router.get('/login',async (ctx)=>{
ctx.body = '网站登录页面';
});
// 启动路由
app
.use(router.routes()) /*启动路由*/
.use(router.allowedMethods()); //作用:当请求出错时处理逻辑
/*
* router.allowedMethods()作用: 这是官方文档的推荐用法,我们可以
* 看到 router.allowedMethods()用在了路由匹配 router.routes()之后,所以在当所有
* 路由中间件最后调用.此时根据 ctx.status 设置 response 响应头
*
*/
// 监听3000端口
app.listen(3000,()=>{
console.log('starting at port 3000');
});
错误处理中间件
Koa是从第一个中间件开始执行,遇到 await next() 就进入下一个中间件,一直到执行到最后一个中间件。然后再逆序执行上一个中间件 await next() 后面的代码,一直到第一个中间件 await next() 后面的代码执行完毕才发出响应。
koa把很多async函数组成一个处理链,每个async函数都可以做一些自己的事情,然后用await next()来调用下一个async函数。我们把每个async函数称为middleware,这些middleware可以组合起来,完成很多有用的功能。
app.use(async (ctx, next) => {
console.log('1');
await next(); // 调用下一个middleware
console.log('5')
});
app.use(async (ctx, next) => {
console.log('2');
await next(); // 调用下一个middleware
console.log('4');
});
app.use(async (ctx, next) => {
console.log('3');
});
输出结果: 12345
在这个例子里,通过输出结果可以看出三个中间件的执行顺序是:
中间件1 -> 中间件2 -> 中间件3 -> 中间件2 -> 中间件1
koa 中间件的执行流程,如下代码访问/news
路由
// 引入Koa模块
const Koa = require('koa');
// 引入Koa-router
const Router = require('koa-router');
// 实例化Koa模块
const app = new Koa();
// 实例化路由模块
const router = new Router();
// Koa 中间件
// app.use('/',function(){}); //可以写两个参数,第一个是匹配的路径,第二个是回调函数,第一个参数可以省略
// 因为不管app.use 和router 的书写顺序是怎样的,都会先执行app.use,所以这个写在开头和写在结尾效果都是一样的
app.use(async (ctx,next)=>{
console.log('1、这是第一个中间件');
await next(); //当前路由匹配完成以后继续向下匹配
console.log('5、匹配路由完成以后又会回来执行中间件');
});
app.use(async (ctx,next)=>{
console.log('2、这是第二个中间件');
await next(); //当前路由匹配完成以后继续向下匹配
console.log('4、匹配路由完成以后又会回来执行中间件');
});
// 配置路由
// ctx 上下文 context, 包含了request和response等信息
router.get('/',async (ctx)=>{
console.log('网站首页');
ctx.body = '网站首页'; //返回数据 相当于:原生里面的res.writeHead() res.end()
});
router.get('/news',async (ctx)=>{
console.log('3、匹配到了这个新闻列表页面');
ctx.body = '新闻列表页面';
});
router.get('/login',async (ctx)=>{
console.log('网站登录页面');
ctx.body = '网站登录页面';
});
// 启动路由
app
.use(router.routes()) /*启动路由*/
.use(router.allowedMethods()); //作用:当请求出错时处理逻辑
/*
* router.allowedMethods()作用: 这是官方文档的推荐用法,我们可以
* 看到 router.allowedMethods()用在了路由匹配 router.routes()之后,所以在当所有
* 路由中间件最后调用.此时根据 ctx.status 设置 response 响应头
*
*/
// 监听3000端口
app.listen(3000,()=>{
console.log('starting at port 3000');
});
打印结果:
1、这是第一个中间件
2、这是第二个中间件
3、匹配到了这个新闻列表页面
4、匹配路由完成以后又会回来执行中间件
5、匹配路由完成以后又会回来执行中间件