【Koa基本使用】
简介
koa 是由 Express 原班人马打造的,致力于成为一个更小、更富有表现力、更健壮的 Web 框架。使用 koa 编写 web 应用,通过组合不同的 generator,可以免除重复繁琐的回调函数嵌套,并极大地提升错误处理的效率。koa 不在内核方法中绑定任何中间件,它仅仅提供了一个轻量优雅的函数库,使得编写 Web 应用变得得心应手。
快速开始
安装koa2
1 2 3 4 5 npm init npm install koa
hello world 代码
1 2 3 4 5 6 7 8 const Koa = require ('koa' )const app = new Koa ()app.use ( async ( ctx ) => { ctx.body = 'hello koa2' }) app.listen (3000 )
启动
koa vs express
通常都会说 Koa 是洋葱模型,这重点在于中间件的设计。但是按照上面的分析,会发现 Express 也是类似的,不同的是Express 中间件机制使用了 Callback 实现,这样如果出现异步则可能会使你在执行顺序上感到困惑,因此如果我们想做接口耗时统计、错误处理 Koa 的这种中间件模式处理起来更方便些。最后一点响应机制也很重要,Koa 不是立即响应,是整个中间件处理完成在最外层进行了响应,而 Express 则是立即响应。
更轻量
koa 不提供内置的中间件;
koa 不提供路由,而是把路由这个库分离出来了(koa/router)
Context对象
koa增加了一个Context的对象,作为这次请求的上下文对象(在koa2中作为中间件的第一个参数传入)。同时Context上也挂载了Request和Response两个对象。和Express类似,这两个对象都提供了大量的便捷方法辅助开发, 这样的话对于在保存一些公有的参数的话变得更加合情合理
异步流程控制
express采用callback来处理异步, koa v1采用generator,koa v2 采用async/await。
generator和async/await使用同步的写法来处理异步,明显好于callback和promise,
中间件模型
express基于connect中间件,线性模型;
koa中间件采用洋葱模型(对于每个中间件,在完成了一些事情后,可以非常优雅的将控制权传递给下一个中间件,并能够等待它完成,当后续的中间件完成处理后,控制权又回到了自己)
alt=“image-20220417083817823”> style=“zoom:50%;float:left;” />
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 35 36 37 var express = require ("express" )var app = express ()app.use ((req,res,next )=> { console .log (1 ) next () console .log (4 ) res.send ("hello" ) }) app.use (()=> { console .log (3 ) }) app.listen (3000 ) var express = require ("express" )var app = express ()app.use (async (req,res,next)=>{ console .log (1 ) await next () console .log (4 ) res.send ("hello" ) }) app.use (async ()=>{ console .log (2 ) await delay (1 ) console .log (3 ) }) function delay (time ){ return new Promise ((resolve,reject )=> { setTimeout (resolve,1000 ) }) }
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 35 36 37 38 39 var koa = require ("koa" )var app = new koa ()app.use ((ctx,next )=> { console .log (1 ) next () console .log (4 ) ctx.body ="hello" }) app.use (()=> { console .log (3 ) }) app.listen (3000 ) var koa = require ("koa" )var app = new koa ()app.use (async (ctx,next)=>{ console .log (1 ) await next () console .log (4 ) ctx.body ="hello" }) app.use (async ()=>{ console .log (2 ) await delay (1 ) console .log (3 ) }) function delay (time ){ return new Promise ((resolve,reject )=> { setTimeout (resolve,1000 ) }) } app.listen (3000 )
4. 路由
基本用发
1 2 3 4 5 6 7 8 9 10 11 var Koa = require ("koa" )var Router = require ("koa-router" )var app = new Koa ()var router = new Router ()router.post ("/list" ,(ctx )=> { ctx.body =["111" ,"222" ,"333" ] }) app.use (router.routes ()).use (router.allowedMethods ()) app.listen (3000 )
router.allowedMethods作用
请求方式
Koa-router 请求方式: get
、 put
、 post
、 patch
、 delete
、 del
,而使用方法就是 router.方式()
,比如 router.get()
和 router.post()
。而 router.all()
会匹配所有的请求方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 var Koa = require ("koa" )var Router = require ("koa-router" )var app = new Koa ()var router = new Router ()router.get ("/user" ,(ctx )=> { ctx.body =["aaa" ,"bbb" ,"ccc" ] }) .put ("/user/:id" ,(ctx )=> { ctx.body ={ok :1 ,info :"user update" } }) .post ("/user" ,(ctx )=> { ctx.body ={ok :1 ,info :"user post" } }) .del ("/user/:id" ,(ctx )=> { ctx.body ={ok :1 ,info :"user del" } }) app.use (router.routes ()).use (router.allowedMethods ()) app.listen (3000 )
拆分路由
routes/list.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var Router = require ("koa-router" )var router = new Router ()router.get ("/" ,(ctx )=> { ctx.body =["111" ,"222" ,"333" ] }) .put ("/:id" ,(ctx )=> { ctx.body ={ok :1 ,info :"list update" } }) .post ("/" ,(ctx )=> { ctx.body ={ok :1 ,info :"list post" } }) .del ("/:id" ,(ctx )=> { ctx.body ={ok :1 ,info :"list del" } }) module .exports = router
routes/index.js
1 2 3 4 5 6 7 8 9 10 var Router = require ("koa-router" )var user = require ("./user" )var list = require ("./list" )var router = new Router ()router.use ('/user' , user.routes (), user.allowedMethods ()) router.use ('/list' , list.routes (), list.allowedMethods ()) module .exports = router
entry入口
1 2 3 4 5 6 var Koa = require ("koa" )var router = require ("./routes" )var app = new Koa ()app.use (router.routes ()).use (router.allowedMethods ()) app.listen (3000 )
路由前缀
1 2 router.prefix ('/api' ) router.use ('/user' , user.routes (), user.allowedMethods ())
路由重定向
1 2 3 4 5 6 7 8 9 10 router.get ("/home" ,(ctx )=> { ctx.body ="home页面" }) router.redirect ('/' , '/home' ); router.get ("/" ,(ctx, next )=> { ctx.redirect ("/home" ) })
静态资源
1 2 3 4 5 6 7 8 9 10 11 12 13 const Koa = require ('koa' )const path = require ('path' )const static = require ('koa-static' )const app = new Koa ()app.use (static (path.join ( __dirname, "public" ))) app.use ( async ( ctx ) => { ctx.body = 'hello world' }) app.listen (3000 )
获取请求参数
get参数
在koa中,获取GET请求数据源头是koa中request对象中的query
方法或querystring
方法。
query返回是格式化好的参数对象,querystring返回的是请求字符串,由于ctx对request的API有直接引用的方式,所以获取GET请求数据有两个途径。
从上下文中直接获取 请求对象ctx.query,返回如 { a:1, b:2 } 请求字符串 ctx.querystring,返回如 a=1&b=2
从上下文的request对象中获取 请求对象ctx.request.query,返回如 { a:1, b:2 } 请求字符串 ctx.request.querystring,返回如 a=1&b=2
post参数
对于POST请求的处理,koa-bodyparser中间件可以把koa2上下文的formData数据解析到ctx.request.body中
1 2 3 4 const bodyParser = require ('koa-bodyparser' )app.use (bodyParser ())
ejs模板
安装模块
1 2 3 4 5 npm install --save koa-views npm install --save ejs
使用模板引擎
文件目录
1 2 3 4 ├── package.json ├── index.js └── view └── index.ejs
./index.js文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const Koa = require ('koa' )const views = require ('koa-views' )const path = require ('path' )const app = new Koa ()app.use (views (path.join (__dirname, './view' ), { extension : 'ejs' })) app.use ( async ( ctx ) => { let title = 'hello koa2' await ctx.render ('index' , { title : 'hello world' , }) }) app.listen (3000 )
./view/index.ejs 模板
1 2 3 4 5 6 7 8 9 10 <!DOCTYPE html> <html> <head> <title><%= title %></title> </head> <body> <h1><%= title %></h1> <p>EJS Welcome to <%= title %></p> </body> </html>
cookie&session
cookie
koa提供了从上下文直接读取、写入cookie的方法
ctx.cookies.get(name, [options]) 读取上下文请求中的cookie
ctx.cookies.set(name, value, [options]) 在上下文中写入cookie
session
图片上传
环境
koa:用来起一个web服务器
koa2-cors: 解决跨域问题
koa-router: koa的路由处理
koa-body: koa参数的获取
koa-static: 静态资源配置
@koa/multer和multer:图片上传的插件
代码结构
实现
第一步:用koa+koa-router搭建一个简单的web服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 const Koa = require ('koa' ) const Router = require ('koa-router' ) const { koaBody } = require ('koa-body' );var router = new Router ()router.get ('/' , async (ctx) => { ctx.type = 'html' ctx.body = '<h1>hello world!</h1>' }).post ('/upload' , async (ctx) => { ctx.body = 'ok' }) app.use (koaBody ()) .use (router.routes ()) .use (router.allowedMethods ()) app.listen (3000 )
现在我们就可以打开http://localhost:3000看到 hello world
接着我们新建一个upload文件夹,且在代码中加入静态内容的的代码
1 2 3 4 5 6 7 const static = require ('koa-static' )const path = require ('path' )app.use (router.routes ()) .use (router.allowedMethods ()) .use (static (path.join (__dirname, './upload' )))
此时假如你在upload文件夹下新增一张照片便可通过http://localhost:3000/***.png 查看到了。(***:你自己新增的照片名称加后缀)
此时新增一个index.html文件,且加入以下代码
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 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta http-equiv ="X-UA-Compatible" content ="IE=edge" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > Document</title > </head > <body > <input type ="file" class ="file" name ="avatar" > <button onclick ="send()" > 上传</button > <script src ="https://unpkg.com/axios/dist/axios.min.js" > </script > <script > let formData = new FormData () document .querySelector ('.file' ).addEventListener ('change' , function (e ) { let files = e.target .files console .log (files) if (!files.length ) return formData.append ('file' , files[0 ], files[0 ].name ) }) function send ( ){ axios.post ('http://localhost:3000/upload' ,formData,{ Headers :{ "Content-type" :"multipart/form-data" } }) } </script > </body > </html >
选择图片且上传会发现存在跨域问题,那么发现问题解决问题直接上代码:
1 2 3 4 5 6 7 8 9 const cors = require ('koa2-cors' )app.use (cors ()) .use (koaBody ()) .use (router.routes ()) .use (router.allowedMethods ()) .use (static (path.join (__dirname, './upload' )) )
解决完跨域后,选择图片且上传,此时咱们已经拿到传过来的数据啦,重头戏来了:@koa/multer使用
1 2 3 4 5 6 7 8 9 10 11 const multer = require ('@koa/multer' )const storage = multer.diskStorage ({ destination : function (req, file, cb ) { cb (null , './upload' ) }, filename : function (req, file, cb ) { const fileFormat = (file.originalname ).split ('.' ) cb (null , Date .now () + '.' + fileFormat[fileFormat.length - 1 ]) } }) const upload = multer ({ storage })
配置好后修改/upload
1 2 3 router.post ('/upload' , upload.single ('file' ), async (ctx) => { console .log ('ctx.file' , ctx.file ) })
note:需要注意的是upload.single('file'),中的file需要和上方的index.html中的formData字段一致
此时就可以愉快的上传啦~~~
记录日志
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 const Koa = require ('koa' )const Router = require ('koa-router' )const logger = require ('koa-logger' )const app = new Koa ()const router = new Router ()app.use (logger ((str, args ) => { })) router.get ('/' , ctx => { ctx.body = '首页' }) app.use (router.routes ()) app.listen (3000 , () => { console .log ('listen 3000 ok' ); })
在注册 koa-logger 中间件时可以传递一个函数,该函数有2个参数
str 是一个字符串类型,在发生请求时 str 包含 请求类型、请求路径信息,在发生响应时 str 包含 响应状态码、响应时长、响应文件大小信息。
args 是一个数组类型,在发生请求时会将请求类型、请求路径放在该数组中,在发生响应时会将响应状态码、响应时长、响应文件大小信息放入该数组中
文件上传