聊聊 koa 中间件

前言

koa是基于Node.js平台的下一代web开发框架,它体积小,扩展性强,给人一种干净利落的编程方式,且由express原班人马打造,国内很多互联网公司都在使用,因此有必要学习总结下。

初出茅庐,来个hello word

  • 按照惯例,先来个demo 输出hello world
 
  1. let Koa = require('koa'); //引入koa

  2. let app = new Koa(); //声明一个实例app

  3. app.use(async (ctx,next)=>{ // 对于任何请求,app将调用该异步函数处理请求:

  4. ctx.body = "hello"

  5. });

  6. app.listen("3000"); //监听端口

  7. 复制代码

  • 其中参数ctx是由koa传入的封装了request和response的变量,我们可以通过它访问request和response。
  • next是koa传入的将要处理的下一个异步函数。
  • 由async标记的函数称为异步函数,在异步函数中,可以用await调用另一个异步函数,这个异步函数必须返回一个promise,上篇文章写过promise用法和实现原理,不了解可以先去看看。这两个关键字将在ES7中引入。

 

 

 

简捷的5行代码,帮我们开启了3000端口的服务

深入理解Koa中间件之洋葱模型

学习Koa重点在于理解中间件实现原理,对后续引用第三方库中间件时候有更好了解。我们单独讲讲

  • 先来段测试代码
 
  1. let Koa = require('koa');

  2. let app = new Koa();

  3. app.use(async (ctx,next)=>{

  4. console.log(1);

  5. await next();

  6. console.log(2);

  7. });

  8. app.use(async (ctx,next)=>{

  9. console.log(3);

  10. await next();

  11. console.log(4);

  12. });

  13. app.listen("3000");

  14. 复制代码

你可能对运行的结果会说 1234,其实不然,我们先来看下输出结果

 

 

 

 

 

 

一脸懵逼1342,这是什么顺序,这就是我们要说的洋葱模型

  • 中间件的执行很像一个洋葱,但并不是一层一层的执行,而是以next为分界,先执行本层中next以前的部分,当下一层中间件执行完后,再执行本层next以后的部分。
  • 一个洋葱结构,从上往下一层一层进来,再从下往上一层一层回去,是不是有点感觉了。

 

 

 

1、koa-router中间件

koa-router基础写法

  • 为了讲的详细全面,把路由分为及部分来讲解,先来看最基本的路由怎么写
 
  1. let Koa = require('koa');

  2. let app = new Koa();

  3. let Router = require('koa-router');

  4. let router = new Router();

  5. router.get('/',async (ctx,next)=>{

  6. ctx.body = 'hello people';

  7. await next()

  8. });

  9. router.get('/list',async (ctx,next)=>{

  10. ctx.body = 'list';

  11. });

  12. app.use(router.routes()); // 挂载

  13. app.use(router.allowedMethods());//当请求数据的方法与设置的方法不一致,会报错。比如默认get请求获取,用post发请求会报错

  14. app.listen(3000);

  15. 复制代码

koa-router中嵌套路由写法

假如我们想为单个页面设置层级,/home是我们首页,再次基础上有/home/list 首页列表页 /home/todo 首页todo页。这时我们就需要用到嵌套路由,看看怎么用

 
  1. const Koa = require('koa');

  2. const app = new Koa();

  3. const Router = require('koa-router');

  4. //home的路由

  5. let home = new Router();

  6. home.get('/list',async(ctx)=>{

  7. ctx.body="Home list";

  8. }).get('/todo',async(ctx)=>{

  9. ctx.body ='Home ToDo';

  10. });

  11. //page的路由

  12. let page = new Router();

  13. page.get('/list',async(ctx)=>{

  14. ctx.body="Page list";

  15. }).get('/todo',async(ctx)=>{

  16. ctx.body ='Page todo';

  17. });

  18. //装载所有子路由

  19. let router = new Router();

  20. router.use('/home',home.routes(),home.allowedMethods());

  21. router.use('/page',page.routes(),page.allowedMethods());

  22. //加载路由中间件

  23. app.use(router.routes()).use(router.allowedMethods());

  24. app.listen(3000);

  25.  
  26. 复制代码

这样一来就实现嵌套路由的写法

 

 

 

koa-router参数的传递

  • 1、通过/arcicle/id/name传参
 
  1. let Koa = require('koa');

  2. let app = new Koa();

  3. let Router = require('koa-router');

  4. let router = new Router();

  5. //实现 /arcicle/id/name形式的传参

  6. router.get('/acticle/:id/:name',(ctx,next)=>{

  7. ctx.body = ctx.params.id +"-"+ ctx.params.name;

  8. });

  9. app.use(router.routes());

  10. app.listen(3000);

  11. 复制代码

测试下,学过vue应该比较熟悉

 

  • 2、通过/arcicle?id=1&name=cgp传参
 
  1. const Koa = require('koa');

  2. const Router = require('koa-router');

  3. const app = new Koa();

  4. const router = new Router();

  5. router.get('/article', function (ctx, next) {

  6. ctx.body=ctx.query; //query方法实现json形式

  7. });

  8. app.use(router.routes())

  9. app.listen(3000,()=>{

  10. console.log('starting at port 3000');

  11. });

  12. 复制代码

 

 

 

2、koa-bodyparse()中间件

  • 用来解析请求体的中间件,比如获取post提交的表单数据,通过koa-bodyparse解析后就能获取到数据。看demo
 
  1. let Koa = require('koa');

  2. let bodyParser = require('koa-bod')

  3. let app = new Koa();

  4. app.use(bodyParser()); // 解析请求体的中间件

  5. app.use(async (ctx, next) => {

  6. if (ctx.path === '/' && ctx.method === 'GET') {

  7. ctx.set('Content-Type', 'text/html;charset=utf8');

  8. ctx.body = `

  9. <form action="/" method="post">

  10. <input type="text" name="username" >

  11. <input type="text" name="password" >

  12. <input type="submit" >

  13. </form>

  14. `

  15. }

  16. });

  17. app.use(async (ctx, next) => {

  18. if (ctx.method === 'POST' && ctx.path === '/') {

  19. // 获取表单提交过来的数据

  20. ctx.body = ctx.request.body;

  21. }

  22. });

  23. app.listen(3000);

  24.  
  25. 复制代码

当post提交表单获得表单数据,测试下结果

 

 

 

3、koa-better-body中间件

  • 是用来上传文件的中间件
  • 由于老的中间件都是基于koa1版本的generate函数实现的,在koa2中我们需要用koa-convert,可以将他们转为基于Promise的中间件供Koa2使用

来个demo体验下,我们把本地的1.txt文件上传到upload文件夹中。 1.txt内容为123456789

 
  1. let Koa = require('koa');

  2. let app = new Koa();

  3. let betterBody = require('koa-better-body'); // v1插件

  4. let convert = require('koa-convert'); // 将1.0的中间件 转化成2.0中间件

  5. app.use(convert(betterBody({

  6. uploadDir: __dirname //指定上传的目录 __dirname当前文件夹绝对路径

  7. })))

  8. app.use(async (ctx, next) => {

  9. if (ctx.path === '/' && ctx.method === 'GET') {

  10. ctx.set('Content-Type', 'text/html;charset=utf8');

  11. ctx.body = `

  12. <form action="/" method="post" enctype="multipart/form-data">

  13. <input type="text" name="username" autoComplete="off">

  14. <input type="text" name="password" autoComplete="off">

  15. <input type="file" name="avatar">

  16. <input type="submit" >

  17. </form>

  18. `

  19. } else {

  20. return next();

  21. }

  22. });

  23. app.use(async (ctx, next) => {

  24. if (ctx.method === 'POST' && ctx.path === '/') {

  25. // 获取表单提交过来的数据

  26. ctx.body = ctx.request.fields;

  27. }

  28. });

  29. app.listen(1000);

  30. 复制代码

看下上传结果

 

 

 

内容也是正确的,我就不给大家展示拉

4、kao-views中间件

  • koa-views对需要进行视图模板渲染的应用是个不可缺少的中间件,支持ejs, nunjucks等众多模板引擎。

我们以ejs为例子

 
  1. let Koa = require('koa');

  2. let app = new Koa();

  3. let views = require('koa-views');

  4. app.use(views(__dirname,{

  5. extension:'ejs' //指定用ejs模板

  6. }));

  7. app.use(async (ctx,next)=>{

  8. // 渲染index.ejs

  9. await ctx.render('index',{name:'cgp',age:9,arr:[1,2,3]});

  10. });

  11. app.listen(3000);

  12. 复制代码

 
  1. <!DOCTYPE html>

  2. <html lang="en">

  3. <head>

  4. <meta charset="UTF-8">

  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">

  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">

  7. <title>Document</title>

  8. </head>

  9. <body>

  10. <h1><%=name%></h1>

  11. <h1><%=age%></h1>

  12. <ul>

  13. <%arr.forEach(item=>{%>

  14. <li><%=item%></li>

  15. <%})%>

  16. </ul>

  17. </body>

  18. </html>

  19.  
  20. 复制代码

  • 我们这里写的模板很简单,就是输出下name、age,然后循环下数组

 

 

 

5、koa-static

 
  1. let Koa = require('koa');

  2. let server = require('koa-static');

  3. let app = new Koa();

  4. app.use(server(__dirname +'/public'));

  5. app.listen(3000);

  6. 复制代码

6、koa自带cookie用法

比如我们要存储用户名,保留用户登录状态时,会用到cookie。

共两个方法

  • ctx.cookies.get()
  • ctx.cookies.set()

先来个demo测试,当输入/write写入cookie,当输入/read读到cookie

 
  1. let Koa = require('koa');

  2. let Router = require('koa-router');

  3. let app = new Koa();

  4. let router = new Router();

  5. router.get('/read', (ctx, next) => {

  6. //有name读name

  7. let name = ctx.cookies.get("name") || '没有name';

  8. let age = ctx.cookies.get("age") || '没有age';

  9. ctx.body = `${name}-${age}`;

  10. });

  11. router.get('/write', (ctx, next) => {

  12. ctx.cookies.set('name', 'cgp',{

  13. domain:'127.0.0.1', //写入cookie所在的域名

  14. path:'/write', // 写入cookie最大的路径

  15. maxAge:10*1000, //Cookie最大有效时长

  16. httpOnly:false, // 是否只用于http请求中获取

  17. overwrite:false // 是否允许重写

  18. });

  19. ctx.cookies.set('age', '9');

  20. ctx.body = 'write Ok';

  21. });

  22. app.use(router.routes());

  23. app.listen(4000);

  24. 复制代码

Cookie选项

  • domain:写入cookie所在的域名
  • path:写入cookie所在的路径
  • maxAge:Cookie最大有效时长
  • expires:cookie失效时间
  • httpOnly:是否只用http请求中获得
  • overwirte:是否允许重写

看下运行结果吧

 

 

 

未完待续

对常用中间件源码感兴趣可以参考下我总结

更多阅读原文可以看这里


转载:https://juejin.im/post/5b5e780cf265da0f6b7713a8

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值