Koa2
简介
- 官网
- koa2是express同一个团队开发的一个新的Web框架;
- 相对于express具有更强的异步处理能力;**(Koa框架的next()函数返回的是一个promise)**
- Koa2的核心代码只有1600+行,是一个更加轻量级的框架,我们可以根据需要安装和使用中间件;
使用
- node下载koa模块
- 命令:
- 初始化服务:
npm init -y
- 下载koa:
npm i koa
koa2初体验
PS:我一直以为是koa,然后群友说koa2,我才发现我用的是koa2;
Koa vs Express && Koa1 vs Koa2;什么是KOA2?KOA2和KOA的差别;
- koa2并没有像express一样,将req和res分开,而是将它们作为 ctx的属性;
- ctx代表依次请求的上下文对象;
- ctx.request:获取请求对象;(koa封装的请求对象)
- ctx.response:获取响应对象;(koa封装的响应对象)
- ctx.req:(Node封装的请求对象)
- ctx.res:(Node封装的响应对象)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| const Koa = require("koa");
const app = new Koa();
app.use((ctx, next) => {
ctx.body = "hello world"; });
app.listen(3000, () => { console.log("server is running port is 3000"); });
|
koa2中间件
koa注册中间件没有methods方式,只有use;且use第一个参数不能设置为路径;且不能连续注册中间件;
- 即:没有提供以下的注册方式:
- methods方式:app.get()/.post()
- 第一个参数为路径:app.use(“/home”,(ctx,next)=>{})
- 连续注册中间件:app.use((ctx,next)=>{},(ctx,next)=>{},(ctx,next)=>{})
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| const Koa = require("koa");
const app = new Koa();
app.use((ctx, next) => { ctx.response.body = "hello world"; if (ctx.request.url == "/login") { if (ctx.request.method == "GET") { ctx.response.body = "login success" } } else { ctx.response.body = "login flase" }
})
app.listen(3000, () => { console.log("server is running port is 3000"); })
|
不难发现,上面请求方式,路径之类的都需要我们自己来做判断,写法太复杂了,那如何简单化呢?答案是使用koa的路由。
koa2路由
在express
中,router
是集成在框架中的;由于koa
是个轻量级的框架,所以没有集成路由,我们需要安装第三方库npm i koa-router
;路由里面有 get post put......
- 我们可以先封装一个 router的 user.js 的文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const Router = require("koa-router");
const router = new Router({prefix:"/users"});
router.get("/",(ctx,next)=>{ ctx.response.body="user lists~" })
router.put("/",(ctx,next)=>{ ctx.response.body="put request~" })
module.exports=router;
|
- 在app中引入 user.js文件,然后通过
app.use()
将其注册为中间件;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
const Koa = require("koa");
const app =new Koa();
const userRouter = require("./router/user.js"); app.use(userRouter.routes());
app.use(userRouter.allowedMethods());
app.listen(3000,()=>{ console.log("server is running port is 3000"); })
|
POST请求body参数解析
中间件应用 - json-urlencoded 解析
在express
中,body-parser
是集成在框架中的;由于koa
是个轻量级的框架,所以没有集成路由,我们需要安装第三方库npm i koa-bodyparser
;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const Koa = require("koa");
const app =new Koa();
const bodyparser = require("koa-bodyparser"); app.use(bodyparser());
app.use((ctx,next)=>{ console.log(ctx.request.body); ctx.response.body="POST请求~~"; })
app.listen(3000,()=>{ console.log("server is running port is 3000"); })
|
form-data 解析:一般用于上传图片文件;
同express
一样,框架没有内置解析form-data
的库,需要下载:npm i koa-multer
;
初步使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| const Koa = require("koa");
const app =new Koa();
const Router = require("koa-router");
const multer = require("koa-multer"); const upload =multer(); app.use(upload.any());
app.use((ctx,next)=>{ console.log(ctx.req.body); ctx.response.body="POST请求form-data参数,不常用,基本用来传文件~"; })
app.listen(3000,()=>{ console.log("server is running port is 3000"); })
|
文件上传
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| const path= require("path"); const Koa =require("koa"); const Router = require("koa-router"); const multer = require("koa-multer");
const app =new Koa(); const uploadRouter = new Router({prefix:"/upload"}); app.use(uploadRouter.routes());
const storage =multer.diskStorage({ destination:(req,file,cb)=>{ cb(null,"./uploads/") }, filename:(req,file,cb)=>{ cb(null,Date.now()+path.extname(file.originalname)); } }) const upload =multer({ storage, });
uploadRouter.post("/avator",upload.single("avatorss"),(ctx,next)=>{ console.log(ctx.req.file); ctx.response.body="文件上传成功!" })
app.listen(3000,()=>{ console.log("server is running port is 3000") })
|
GET请求参数解析
params获取路由参数;request获取地址栏?之后的参数;下面是两者结合的demo;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| const Koa = require("koa");
const app =new Koa();
const Router = require("koa-router"); const userRouter = new Router({prefix:"/users"})
app.use(userRouter.routes()); app.use(userRouter.allowedMethods());
userRouter.get("/:id",(ctx,next)=>{ console.log(ctx.request.params); console.log(ctx.request.query); ctx.response.body="GET请求~~"; })
app.listen(3000,()=>{ console.log("server is running port is 3000"); })
|
响应数据
- 输出结果:body将响应主体设置为以下之一:
- string :字符串数据
- Buffer :Buffer数据
- Stream :流数据
- Object|| Array:对象或者数组
- null :不输出任何内容
- 如果response.status尚未设置,Koa会自动将状态设置为200或204。
- ctx.response.body 可以简写为 ctx.body
- ctx.status=xxx 设置状态码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| const Koa = require("koa");
const app = new Koa();
app.use((ctx, next) => {
ctx.status = 400; ctx.body = "hahahaa"; })
app.listen(3000, () => { console.log("Server is running port is 3000") })
|
错误处理
使用ctx.app.emit("error",new Error("xxxx"),ctx)
传参;(第一个”error”的监听错误信息,第二个是传递的错误信息参数,第三个是ctx参数)
使用app.on("error",(error,ctx)=>{})
接收错误信息;(第一个”error”的监听错误信息,第二个是回调函数,接收传送来的 错误信息参数和ctx参数)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| const Koa = require("koa");
const app = new Koa();
app.use((ctx,next)=>{ const isLogin =false; if(!isLogin){ ctx.app.emit("error",new Error("您还没有登录"),ctx); } })
app.on("error",(err,ctx)=>{ ctx.status=401; ctx.body=err.message; })
app.listen(3000,()=>{ console.log("Server is running port is 3000") })
|
Koa2与express区别
- 从架构设计上来说:
- express是完整和强大的,其中帮助我们内置了非常多好用的功能;
- koa是简洁和自由的,它只包含最核心的功能,并不会对我们使用其他中间件进行任何的限制。
- 甚至是在app中连最基本的get、post都没有给我们提供;
- 我们需要通过自己或者路由来判断请求方式或者其他功能;
- express和koa框架他们的核心其实都是中间件:
- 但是他们的中间件事实上,它们的中间件的执行机制是不同的,特别是针对某个中间件中包含异步操作时;
- 所以,接下来,我们再来研究一下express和koa中间件的执行顺序问题;
案例实现
这里通过一个需求来演示所有的过程;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| const express = require("express"); const app = express();
const middleware1 = (req,res,next)=>{ res.message="aaa"; next(); res.end(res.message); }
const middleware2 = (req,res,next)=>{ res.message+="bbb"; next(); }
const middleware3 = (req,res,next)=>{ res.message+="ccc"; }
app.use(middleware1,middleware2,middleware3);
app.listen(3000,()=>{ console.log("server is running port is 3000"); })
|
Express异步数据的实现;这里使用axios
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| const express = require("express"); const axios = require("axios"); const app = express();
const middleware1 = (req, res, next) => { res.message = "aaa"; next(); }
const middleware2 = (req, res, next) => { res.message += "bbb"; next(); }
const middleware3 = (req, res, next) => { axios.get("https://api.vvhan.com/api/love").then(result => { res.message += result.data; res.end(res.message); })
}
app.use(middleware1, middleware2, middleware3);
app.listen(3000, () => { console.log("server is running port is 3000"); })
|
Koa同步数据的实现;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| const Koa =require("koa"); const app = new Koa();
const middleware1 = (ctx,next)=>{ ctx.message="aaa"; next(); ctx.body=ctx.message; }
const middleware2 = (ctx,next)=>{ ctx.message+="bbb"; next(); }
const middleware3 = (ctx,next)=>{ ctx.message+="ccc"; }
app.use(middleware1); app.use(middleware2); app.use(middleware3);
app.listen(3000, () => { console.log("server is running port is 3000"); })
|
Koa异步数据的实现;koa的next()函数返回的是一个promise
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| const Koa = require("koa"); const axios = require("axios"); const app = new Koa();
const middleware1 = async (ctx, next) => { ctx.message = "aaa"; await next(); ctx.body = ctx.message; }
const middleware2 = async (ctx, next) => { ctx.message += "bbb"; await next(); }
const middleware3 = async (ctx, next) => { const result = await axios.get("https://api.vvhan.com/api/love"); ctx.message += result.data; }
app.use(middleware1); app.use(middleware2); app.use(middleware3);
app.listen(3000, () => { console.log("server is running port is 3000"); })
|