zoukankan      html  css  js  c++  java
  • koa2 从入门到进阶之路 (三)

    之前的文章我们介绍了一下 koa 路由,get 传值,动态路由,本节我们看一下 koa 中间件 以及 koa 中间件的洋葱图执行流程。

    一、什么是 Koa 的中间件

    通俗的讲:中间件就是匹配路由之前或者匹配路由完成做的一系列的操作,我们就可以把它叫做中间件。

    在express中间件(Middleware)是一个函数,它可以访问请求对象(request object (req)), 响应对象(response object (res)), 和 web 应用中处理请求-响应循环流程中的中间件,一般被命名为 next 的变量。在 Koa 中中间件和 express 有点类似。

    中间件的功能包括:

      执行任何代码。

      修改请求和响应对象。

      终结请求-响应循环。

      调用堆栈中的下一个中间件。

    如果我的 get、post 回调函数中,没有 next 参数,那么就匹配上第一个路由,就不会往下匹 配了。如果想往下匹配的话,那么需要写 next()

    二、Koa 应用可使用如下几种中间件:

      应用级中间件

      路由级中间件

      错误处理中间

      第三方中间件

    我们先来看一下应用级中间件,我们还是按照之前的项目将 app.js 改为如下:

     1 //引入 koa模块
     2 var Koa = require('koa');
     3 var Router = require('koa-router');
     4 
     5 //实例化
     6 var app = new Koa();
     7 var router = new Router();
     8 
     9 //匹配任何路由,如果不写next,这个路由被匹配到了就不会继续向下匹配
    10 app.use(async (ctx, next) => {
    11     console.log("我是一个中间件");
    12     // 当前路由匹配完成以后继续向下匹配
    13     await next();
    14 });
    15 
    16 //配置路由
    17 router.get('/', async (ctx) => {
    18     ctx.body = "首页";
    19 });
    20 router.get('/news', async (ctx) => {
    21     ctx.body = "新闻列页面";
    22 });
    23 
    24 //启动路由
    25 app.use(router.routes());
    26 app.use(router.allowedMethods());
    27 
    28 app.listen(3000);

    我们在匹配路由之前写了一个 app.use(async ()=>{}) 的中间件,该中间件如果不像 router.get 那样写一个参数 "/" 或 "/news",那么它将匹配任何一个路由,且最先匹配,如果我们在其中写 next() 的话,则会终止在此,不再向下陪陪路由,运行结果如下:

    我们在编辑器的控制台看一下输出日志:

    接下来我们看一下路由中间件:

     1 //引入 koa模块
     2 var Koa = require('koa');
     3 var Router = require('koa-router');
     4 
     5 //实例化
     6 var app = new Koa();
     7 var router = new Router();
     8 
     9 //配置路由
    10 router.get('/', async (ctx, next) => {
    11     console.log("控制台打印");
    12     // 当前路由匹配完成以后继续向下匹配
    13     await next();
    14 });
    15 router.get('/', async (ctx) => {
    16     ctx.body = "首页";
    17 });
    18 router.get('/news', async (ctx) => {
    19     ctx.body = "新闻列页面";
    20 });
    21 
    22 //启动路由
    23 app.use(router.routes());
    24 app.use(router.allowedMethods());
    25 
    26 app.listen(3000);

    在上面的代码中我们定义了两个 router.get('/',  ) 的路由,第一个我们在控制台输出一句话,第二个我们想页面输出内容。如果在第一个里面我们不写 next() 方法的话,则不会进入第二个里面,结果如下:

    控制台打印结果

    接下来我们看一下错误处理中间件:

     1 //引入 koa模块
     2 var Koa = require('koa');
     3 var Router = require('koa-router');
     4 
     5 //实例化
     6 var app = new Koa();
     7 var router = new Router();
     8 
     9 //匹配任何路由,如果不写next,这个路由被匹配到了就不会继续向下匹配
    10 app.use(async (ctx,next)=>{
    11     await next();
    12     //如果页面找不到
    13     if(ctx.status==404){
    14         ctx.status = 404;
    15         ctx.body="404 页面"
    16     }
    17 });
    18 
    19 //配置路由
    20 router.get('/', async (ctx) => {
    21     ctx.body = "首页";
    22 });
    23 router.get('/news', async (ctx) => {
    24     ctx.body = "新闻列页面";
    25 });
    26 
    27 //启动路由
    28 app.use(router.routes());
    29 app.use(router.allowedMethods());
    30 
    31 app.listen(3000);

    我们还按之前的应用中间件那样写,然后在里面做了一个 if 语句判断,当页面响应时,会给后端返回一个 status 码,这个就不在单独说了,如果这个 status 报 404,我们知道表示该页面不存在,那么我们就可以拦截 next() 方法,输出给前端一个 404 页面,结果如下:

    我们匹配了一个 "/news" 路由,可以正常显示内容,如果我们不小心少写一个 "s",写成了 "new",结果如下:

    在上面的代码中我们是将 if 判断语句放在了 next() 方法之后,那能不能放在 next() 之前呢?这个问题我们在下面的 koa 中间件流程控制中再详细说明。

    第三方中间件在之后的文章中我们用到了第三方模块时再说。

    接下来我么看一下 koa 中的中间件流程控制。

    koa被认为是第二代node web framework,它最大的特点就是独特的中间件流程控制,是一个典型的洋葱模型。

    上面的两张图可以很直观的说明 koa 中的中间件流程控制。我们接下来用代码演示一下:

     1 //引入 koa模块
     2 var Koa = require('koa');
     3 var Router = require('koa-router');
     4 
     5 //实例化
     6 var app = new Koa();
     7 var router = new Router();
     8 
     9 app.use(async (ctx, next) => {
    10     console.log('1、这是第一个中间件01');
    11     await next();
    12     console.log('5、匹配路由完成以后又会返回来执行中间件');
    13 });
    14 
    15 app.use(async (ctx, next) => {
    16     console.log('2、这是第二个中间件02');
    17     await next();
    18     console.log('4、匹配路由完成以后又会返回来执行中间件');
    19 });
    20 
    21 router.get('/', async (ctx) => {
    22     console.log('3、匹配到了news这个路由');
    23     ctx.body = "首页";
    24 });
    25 
    26 //启动路由
    27 app.use(router.routes());
    28 app.use(router.allowedMethods());
    29 
    30 app.listen(3000);

    我们在上面的代码引用了两个应用级的中间件,分别在 next() 前后输出日志,当我们访问 localhost:3000/ 时,我们看一下控制台的输出结果:

    从输出打印结果顺序我们可以看出中间件会先逐级处理 request  请求,然后再返回来逐级处理 response 请求,这就是我们为什么要将 错误处理中间件 中的 if 判断语句放在 next() 方法之后,这样就是在路由进入 "/news" 后返回 status = 404 的结果后再进行处理,如果放在了 next() 方法之前,则会直接判断 if 语句,不会再向下匹配 "/news" 路由了。比如我们的用户登录系统就可以这么用,当用户输入账号密码后出入后台,后台在数据库匹配之后再进行处理,处理之后返回给前端,就是这么玩的。

  • 相关阅读:
    [翻译]NUnitString && Collection && File && Directory Assert (七)
    c++删除指定字符串之间的内容(比正则表达式快几十倍)[转]
    C++ 使用正则表达式分割字符串
    c++正则查找
    PHP的XSS攻击过滤函数
    Boost之正则表达式_[转]
    C++中的类所占内存空间总结[转]
    make_shared() shared_prt()详解区别
    C++ STRING 和WSTRING 之间的互相转换函数 和字符串替换
    LConfig:利用Lua脚本做程序的配置文件 [转]
  • 原文地址:https://www.cnblogs.com/weijiutao/p/10690535.html
Copyright © 2011-2022 走看看