• koa2中间件,路由,cookies


    Koa 中间件采用的是洋葱圈模型,每次执行下一个中间件传入两个参数 ctx 和 next,参数 ctx 是由 koa 传入的封装了 request 和 response 的变量,可以通过它访问 request 和 response,next 就是进入下一个要执行的中间件。

     

    自定义中间件m1, m2,m3,pv, 中间件就是一个函数,向外暴露这个函数 

    pv.js, 在node.js中,全局global,不是window

    function pv(ctx) {
      // ctx.path为路径
      global.console.log("pv", ctx.path);
    }
    
    // 中间件,暴露一个函数
    module.exports = function () {
      return async function (ctx, next) {
        pv(ctx);
        // 执行下一个中间件,没有下一个中间件就执行完了
        await next();
      };
    };

    m1

    function m1(ctx) {
      // ctx.path为路径
      global.console.log("m1", ctx.path);
    }
    
    module.exports = function () {
      return async function (ctx, next) {
        global.console.log("m1-start");
        m1(ctx);
        // 执行下一个中间件,没有下一个中间件就执行完了
        await next();
        global.console.log("m1-end");
      };
    };

    m2

    function m2(ctx) {
      // ctx.path为路径
      global.console.log("m2", ctx.path);
    }
    
    // // 中间件,暴露一个函数
    module.exports = function () {
      return async function (ctx, next) {
        global.console.log("m2-start");
        m2(ctx);
        // 执行下一个中间件,没有下一个中间件就执行完了
        await next();
        global.console.log("m2-end");
      };
    };

    m3

    function m3(ctx) {
      // ctx.path为路径
      global.console.log("m3", ctx.path);
    }
    
    module.exports = function () {
      return async function (ctx, next) {
        global.console.log("m3-start");
        m3(ctx);
        // 执行下一个中间件,没有下一个中间件就执行完了
        await next();
        global.console.log("m3-end");
      };
    };

    在app.js中引入中间件,以及使用

    const Koa = require("koa");
    const app = new Koa();
    const views = require("koa-views");
    const json = require("koa-json");
    const onerror = require("koa-onerror");
    const bodyparser = require("koa-bodyparser");
    const logger = require("koa-logger");
    const pv = require("./middleWare/pv.js");
    const m1 = require("./middleWare/m1.js");
    const m2 = require("./middleWare/m2.js");
    const m3 = require("./middleWare/m3.js");
    
    const index = require("./routes/index");
    const users = require("./routes/users");
    
    // error handler
    onerror(app);
    
    // middlewares, 中间件引入顺序
    app.use(
      bodyparser({
        enableTypes: ["json", "form", "text"],
      })
    );
    app.use(json());
    app.use(pv());
    app.use(m1());
    app.use(m2());
    app.use(m3());
    
    app.use(logger());
    app.use(require("koa-static")(__dirname + "/public"));
    
    app.use(
      views(__dirname + "/views", {
        extension: "ejs",
      })
    );
    
    // logger
    app.use(async (ctx, next) => {
      const start = new Date();
      await next();
      const ms = new Date() - start;
      console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
    });
    
    // routes
    app.use(index.routes(), index.allowedMethods());
    app.use(users.routes(), users.allowedMethods());
    
    // error-handling
    app.on("error", (err, ctx) => {
      console.error("server error", err, ctx);
    });
    
    module.exports = app;

    此时中间件中的逻辑输出顺序,先进后出的顺序,

    原理

    再回到中间件的执行机制,来看看具体是怎么回事。
    我们知道 async 的执行机制是:只有当所有的 await 异步都执行完之后才能返回一个 Promise。所以当我们用 async 的语法写中间件的时候,执行流程大致如下:
    
    先执行第一个中间件(因为compose 会默认执行 dispatch(0)),该中间件返回 Promise,然后被 Koa 监听,执行对应的逻辑(成功或失败)
    在执行第一个中间件的逻辑时,遇到 await next()时,会继续执行 dispatch(i+1),也就是执行 dispatch(1),会手动触发执行第二个中间件。
    这时候,第一个中间件 await next() 后面的代码就会被 pending,等待 await next() 返回 Promise,才会继续执行第一个中间件 await next() 后面的代码。 同样的在执行第二个中间件的时候,遇到 await next() 的时候,会手动执行第三个中间件,await next() 后面的代码依然被 pending,等待 await 下一个中间件的 Promise.resolve。
    只有在接收到第三个中间件的 resolve 后才会执行后面的代码,然后第二个中间会返回 Promise,被第一个中间件的 await 捕获,这时候才会执行第一个中间件的后续代码,然后再返回 Promise 以此类推,如果有多个中间件的时候,会依照上面的逻辑不断执行,先执行第一个中间件,在 await next() 出 pending,继续执行第二个中间件,继续在 await next() 出 pending,
    继续执行第三个中间,直到最后一个中间件执行完,然后返回 Promise,然后倒数第二个中间件才执行后续的代码并返回Promise,然后是倒数第三个中间件,
    接着一直以这种方式执行直到第一个中间件执行完,并返回 Promise,从而实现文章开头那张图的执行顺序。 通过上面的分析之后,如果你要写一个 koa2 的中间件,那么基本格式应该就长下面这样:
    async function koaMiddleware(ctx, next){ try{ // do something await next() // do something } .catch(err){ // handle err } }

    路由,在router-->user.js文件中

    const router = require('koa-router')()
    
    // 路由根路径,可以搞路由模块化
    router.prefix('/users')
    
    // 真正路径/users/
    router.get('/', function (ctx, next) {
      ctx.body = 'this is a users response!'
    })
    
    // 真正路径/users/bar
    router.get('/bar', function (ctx, next) {
      ctx.body = 'this is a users/bar response'
    })
    
    module.exports = router

    cookies的设置与读取

    中文文档;https://www.koajs.com.cn/#context

    router.get("/", async (ctx, next) => {
      // global.console.log("index8");
      ctx.cookies.set('pvid', 1)
      await ctx.render("index", {
        title: "Hello Koa 2!",
      });
    });

    读取

    router.get("/json", async (ctx, next) => {
      ctx.body = {
        title: "koa2 json",
        cookies:ctx.cookies.get('pvid')
      };
    });

  • 相关阅读:
    retain和copy的区别 #import @class 的区别
    UImageview加边框 加阴影
    iOS中有两种支持机制:Notification和KVO(KeyValue Observing)
    Windows上编译,学习Objectivec
    CAAnimation动画
    ObjectiveC 熟记小概念
    cocos2d工具大全
    cocos2d 0.99.5版本屏幕默认是横屏,怎么修改为竖屏呢?
    ObjectiveC 的 self 和 super 详解
    ObjectiveC 的属性与合成方法使用详解
  • 原文地址:https://www.cnblogs.com/fsg6/p/14408677.html
Copyright © 2020-2023  润新知