一.koa框架介绍
Node.js 是一个异步的世界,官方 API 支持的都是 callback 形式的异步编程模型,这 会带来许多问题,例如:1、callback 嵌套问题 2、异步函数中可能同步调用 callback 返回 数据,带来不一致性。为了解决以上问题 Koa 出现了。
Koa – 基于 Node.js 平台的下一代 web 开发框架
koa 是由 Express 原班人马打造的,致力于成为一个更小、更富有表现力、更健壮的 Web 框架。 使用 koa 编写 web 应用,可以免除重复繁琐的回调函数嵌套, 并极大地提 升错误处理的效率。koa 不在内核方法中绑定任何中间件, 它仅仅提供了一个轻量优雅的 函数库,使得编写 Web 应用变得得心应手。开发思路和 express 差不多,最大的特点就是 可以避免异步嵌套。
安装koa
npm install --save koa / cnpm install --save koa
–save 参数,表示自动修改 package.json 文件,自动添加依赖项。
简单使用:
var koa =require('koa');
var app=new koa(); //实例化
//配置路由
//中间件
//express写法
//app.use(function(req,res){
//
// res.send('返回数据')
//})
app.use( async (ctx)=>{
ctx.body='你好 koa2.x';
})
app.listen(3000); //监听3000端口
二.Koa异步处理Async、Await和Promise的使用
async 是“异步”的简写,而 await 可以认为是 async wait 的简写。所以应该很好理解 async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成。
简单理解:
async 是让方法变成异步。
await 是等待异步方法执行完成。
详细说明:
async 是让方法变成异步,在终端里用 node 执行这段代码,你会发现输出了 Promise {‘Hello async’ },这时候会发现它返回的是 Promise。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-npYkLq39-1598271285099)(https://i.loli.net/2020/08/22/vWajMAkbwT4IV97.png)]
await 在等待 async 方法执行完毕,其实 await 等待的只是一个表达式,这个表达式在官方文档里说的是 Promise 对象,但是它也可以接受普通值。 **注意:**await 必须在 async 方法中 才可以使用因为 await 访问本身就会造成程序停止堵塞,所以必须在异步方法中才可以使用。
//async 是让方法变成异步
/*
普通方法
function getData(){
return '这是一个数据';
}
console.log(getData()); //这是一个数据
* */
/*
async 是让方法变成异步
async function getData(){
return '这是一个数据';
}
console.log(getData()); //Promise { '这是一个数据' }
* */
/*如何获取async 异步方法里面的数据的第一种方法
async function getData(){
return '这是一个数据';
}
var p=getData();
p.then((data)=>{
console.log(data);
})
* */
//await 是等待异步方法执行完成,可以获取异步方法里面的数据,但是必须得用在异步方法里面
/*await 错误的用法
async function getData(){
return '这是一个数据';
}
var d=await getData();
console.log(d); //await is only valid in async function
* */
//await 是等待异步方法执行完成,可以获取异步方法里面的数据,但是必须得用在异步方法里面
/*
async function getData(){
return '这是一个数据';
}
async function test(){
var d=await getData();
console.log(d);
}
test();
* */
//await 阻塞的功能 ,把异步改成一个同步
//async function getData(){
// console.log(2);
// return '这是一个数据';
//}
//async function test(){
//
// console.log(1);
// var d=await getData();
// console.log(d);
// console.log(3);
//}
//test(); //1 2 3
//async 定义的方法返回的是 Promise对象。
/*
function getData(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
var username='张三';
resolve(username);
},1000)
})
}
var p=getData();
p.then(function(d){ //异步的方式获取
console.log(d);
})
* */
//async/await 同时使用 async 会将其后的函数(函数表达式或 Lambda)的返回值封装成一个 Promise 对象,而 await 会等待这个 Promise 完成,并将其 resolve 的结果返回出来。
function getData(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
var username='张三';
resolve(username);
},1000)
})
}
async function test(){
var data=await getData();
console.log(data);
}
test();
三.koa路由
路由(Routing)是由一个 URI(或者叫路径)和一个特定的 HTTP 方法(GET、POST 等) 组成的,涉及到应用如何响应客户端对某个网站节点的访问。
通俗的讲:路由就是根据不同的 URL 地址,加载不同的页面实现不同的功能。
安裝koa-router
npm install --save koa-router
//引入 koa模块
var Koa=require('koa');
var Router = require('@koa/router');
//实例化
var app=new Koa();
var router = new Router();
//ctx 上下文 context ,包含了request 和response等信息
//配置路由
router.get('/',async (ctx)=>{
ctx.body='首页'; /*返回数据 相当于:原生里面的res.writeHead() res.end()*/
}).get('/news',async (ctx)=>{
ctx.body="这是一个新闻页面"
})
//启动路由
app
.use(router.routes()) /*启动路由*/
.use(router.allowedMethods()); /*可以配置也可以不配置,建议配置,*/
/*
router.allowedMethods()作用: 这是官方文档的推荐用法,我们可以
看到 router.allowedMethods()用在了路由匹配 router.routes()之后,所以在当所有
路由中间件最后调用.此时根据 ctx.status 设置 response 响应头
*/
app.listen(3000);
四.Koa路由获取get传值
//引入 koa模块
var Koa=require('koa');
var router = require('@koa/router')(); /*引入是实例化路由** 推荐*/
//实例化
var app=new Koa();
router.get('/',async (ctx)=>{
ctx.body="首页";
})
router.get('/news',async (ctx)=>{
ctx.body="新闻列表页面";
})
//获取get传值
//http://localhost:3002/newscontent?aid=123
router.get('/newscontent',async (ctx)=>{
/*在 koa2 中 GET 传值通过 request 接收,但是接收的方法有两种:query 和 querystring。
query:返回的是格式化好的参数对象。
querystring:返回的是请求字符串。*/
//从ctx中读取get传值
console.log(ctx.query); //{ aid: '123' } 获取的是对象 用的最多的方式 ******推荐
console.log(ctx.querystring); //aid=123&name=zhangsan 获取的是一个字符串
console.log(ctx.url); //获取url地址
//ctx里面的request里面获取get传值
console.log(ctx.request.url);
console.log(ctx.request.query); //{ aid: '123', name: 'zhangsan' } 对象
console.log(ctx.request.querystring); //aid=123&name=zhangsan
ctx.body="新闻详情";
})
app.use(router.routes()); /*启动路由*/
app.use(router.allowedMethods());
/*
* router.allowedMethods()作用: 这是官方文档的推荐用法,我们可以
看到 router.allowedMethods()用在了路由匹配 router.routes()之后,所以在当所有
路由中间件最后调用.此时根据 ctx.status 设置 response 响应头*/
app.listen(3002);
五.koa中间件
1.什么是Koa的中间件
**通俗的讲:**中间件就是匹配路由之前或者匹配路由完成做的一系列的操作,我们就可以
把它叫做中间件。
在 express **中间件(Middleware)是一个函数,它可以访问请求对象(request object (req)), 响应对象(response object (res)), 和 web 应用中处理请求-响应循环流程中的中间件,一 般被命名为 next 的变量。在 Koa 中中间件和 express 有点类似。
中间件的功能包括:
执行任何代码。
修改请求和响应对象。
终结请求-响应循环。
调用堆栈中的下一个中间件。
如果我的 get、post 回调函数中,没有 next 参数,那么就匹配上第一个路由,就不会往下匹 配了。如果想往下匹配的话,那么需要写 next()
2.Koa 应用可使用如下几种中间件:
应用级中间件:
//引入 koa模块
var Koa=require('koa');
var router = require('koa-router')(); /*引入是实例化路由** 推荐*/
var app=new Koa();
//Koa中间件
//匹配任何路由 ,如果不写next,这个路由被匹配到了就不会继续向下匹配
/*
app.use(async (ctx)=>{
ctx.body='这是一个中间件';
})
* */
/*匹配路由之前打印日期*/
app.use(async (ctx,next)=>{
console.log(new Date())
await next(); /*当前路由匹配完成以后继续向下匹配*/
})
router.get('/',async (ctx)=>{
ctx.body="首页";
})
router.get('/news',async (ctx)=>{
ctx.body="新闻列表页面";
})
router.get('/login',async (ctx)=>{
ctx.body="新闻列表页面";
})
app.use(router.routes()); /*启动路由*/
app.use(router.allowedMethods());
app.listen(3002);
路由级中间件:
//引入 koa模块
var Koa=require('koa');
var router = require('koa-router')(); /*引入是实例化路由** 推荐*/
var app=new Koa();
//Koa中间件
//匹配任何路由 ,如果不写next,这个路由被匹配到了就不会继续向下匹配
router.get('/',async (ctx)=>{
ctx.body="首页";
})
// 匹配到news路由以后继续向下匹配路由
router.get('/news',async (ctx,next)=>{
console.log('这是一个新闻1');
await next();
})
router.get('/news',async (ctx)=>{
ctx.body='新闻2';
})
router.get('/login',async (ctx)=>{
ctx.body="新闻列表页面";
})
app.use(router.routes()); /*启动路由*/
app.use(router.allowedMethods());
app.listen(3002);
错误处理中间件
//引入 koa模块
var Koa=require('koa');
var router = require('koa-router')(); /*引入是实例化路由** 推荐*/
var app=new Koa();
//Koa中间件
//匹配任何路由 ,如果不写next,这个路由被匹配到了就不会继续向下匹配
//www.域名.com/news
app.use(async (ctx,next)=>{
console.log('这是一个中间件01');
next();
if(ctx.status==404){ /*如果页面找不到*/
ctx.status = 404;
ctx.body="这是一个 404 页面"
}else{
console.log(ctx.url);
}
})
router.get('/',async (ctx)=>{
ctx.body="首页";
})
router.get('/news',async (ctx)=>{
console.log('这是新闻2');
ctx.body='这是一个新闻';
})
router.get('/login',async (ctx)=>{
ctx.body="新闻列表页面";
})
app.use(router.routes()); /*启动路由*/
app.use(router.allowedMethods());
app.listen(3002);
第三方中间件
const static = require('koa-static');
const staticPath = './static';
app.use(static(
path.join( __dirname, staticPath)
))
const bodyParser = require('koa-bodyparser');
app.use(bodyParser());
3.koa中间件处理流程
//Koa 选择了洋葱圈模型
//引入 koa模块
var Koa=require('koa');
var router = require('koa-router')(); /*引入是实例化路由** 推荐*/
var app=new Koa();
//Koa中间件
//匹配任何路由 ,如果不写next,这个路由被匹配到了就不会继续向下匹配
//www.域名.com/news
app.use(async (ctx,next)=>{
console.log('1、这是第一个中间件01');
await next();
console.log('5、匹配路由完成以后又会返回来执行中间件');
})
app.use(async (ctx,next)=>{
console.log('2、这是第二个中间件02');
await next();
console.log('4、匹配路由完成以后又会返回来执行中间件');
})
router.get('/',async (ctx)=>{
ctx.body="首页";
})
router.get('/news',async (ctx)=>{
console.log('3、匹配到了news这个路由');
ctx.body='这是一个新闻';
})
app.use(router.routes()); /*启动路由*/
app.use(router.allowedMethods());
app.listen(3002);
1、这是第一个中间件
2、这是第二个中间件
3、匹配到news路由
4、匹配路由完成以后返回来执行中间件
5、匹配路由完成以后返回来执行中间件
await next();
console.log('5、匹配路由完成以后又会返回来执行中间件');
})
app.use(async (ctx,next)=>{
console.log(‘2、这是第二个中间件02’);
await next();
console.log('4、匹配路由完成以后又会返回来执行中间件');
})
router.get(’/’,async (ctx)=>{
ctx.body="首页";
})
router.get(’/news’,async (ctx)=>{
console.log('3、匹配到了news这个路由');
ctx.body='这是一个新闻';
})
app.use(router.routes()); /启动路由/
app.use(router.allowedMethods());
app.listen(3002);
1、这是第一个中间件
2、这是第二个中间件
3、匹配到news路由
4、匹配路由完成以后返回来执行中间件
5、匹配路由完成以后返回来执行中间件