代码地址:https://github.com/changeclass/Node_Blog_koa2.git

# async 与 await

异步 promise 写法

getFileContent('a.json').then(aData => {
    console.log('a data', aData)
    return getFileContent(aData.next)
}).then(bData => {
    console.log('b data', bData)
    return getFileContent(bData.next)
}).then(cData => {
    console.log('c data', cData)
})

async 与 await 写法

async function readFileData() {
  // 同步写法
  try {
    const aData = await getFileContent("a.json");
    console.log("a data", aData);
    const bData = await getFileContent(aData.next);
    console.log("b data", bData);
    const cData = await getFileContent(bData.next);
    console.log("c data", cData);
  } catch (err) {
    console.error(err);
  }
}
readFileData();
  1. await 后面可以追加 promise 对象,获取 resolve 的值

  2. await 必须包裹在 async 函数里面

  3. async 函数执行返回的也是一个 promise 对象

  4. try-catch 截获 promisereject 的值

# koa2

  1. 安装 koa2

    npm install koa-generator -g
  2. 初始化项目

    koa2 blog-koa2

    image-20201022112031101

  3. 安装环境参数的插件

    yarn add cross-env --dev
  4. 运行项目

    yarn run dev

    image-20201022112417855

    默认端口为 3000

# 路由

koa2 使用路由需要单独引用 koa-router 插件。其余与 express 类似。但是有几点需要注意:

  • 中间件必须是 async 函数
  • 中间件函数
    • 第一个参数 ctx 表示 request 与 response 的集合体
    • 第二个参数 next 与 express 一样
const router = require('koa-router')()
router.get('/', async (ctx, next) => {
  await ctx.render('index', {
    title: 'Hello Koa 2!'
  })
})
router.get('/string', async (ctx, next) => {
  ctx.body = 'koa2 string'
})
router.get('/json', async (ctx, next) => {
  ctx.body = {
    title: 'koa2 json'
  }
})
module.exports = router

image-20201022142828775

如果使用前缀需要调用 prefix 方法。例如:

const router = require('koa-router')()
router.prefix('/users')
router.get('/', function (ctx, next) {
  ctx.body = 'this is a users response!'
})
router.get('/bar', function (ctx, next) {
  ctx.body = 'this is a users/bar response'
})
module.exports = router

image-20201022144230445

# 添加自己的路由

首先添加一个获取博客列表的路由。

  1. routes 文件夹新建一个 blog.js 文件

    const router = require("koa-router")();
    // 定义前缀
    router.prefix("/api/blog");
    // 路由 /api/blog/list
    router.get("/list", async function (ctx, next) {
      const query = ctx.query;
      ctx.body = {
        errno: 0,
        query,
        data: ["博客列表"],
      };
    });
    module.exports = router;
  2. app.js 中引入文件

    const blog = require("./routes/blog");
  3. app.js 中注册路由

    app.use(blog.routes(), blog.allowedMethods());

image-20201022144955571

# 中间件机制

基本上与 express 中间件一样

// 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`);
});

# 实现 session

  1. 安装插件

    yarn add koa-generic-session koa-redis redis
  2. app.js 中引入这两个工具

    const session = require("koa-generic-session");
    const redisStore = require("koa-redis");
  3. 在处理路由之前配置 session

    //session 配置
    app.keys = ["12323213sad"]; // 设置 session 加密密匙
    app.use(
      session({
        cookie: {
          path: "/",
          httpOnly: true,
          maxAge: 24 * 60 * 60 * 1000,
        },
        store: redisStore({
          all: "127.0.0.1:6379", // 写死本地的 server
        }),
      })
    );
  4. 测试

    router.get("/session-test", async function (ctx, next) {
      console.log(ctx.session);
      if (ctx.session.viewCount == null) {
        ctx.session.viewCount = 0;
      }
      ctx.session.viewCount++;
      ctx.body = {
        errno: 0,
        viewCount: ctx.session.viewCount,
      };
    });

    e07a70c5-77b7-43c2-bc85-830ba5c583f8

# 开发路由 - 准备工作

  1. 安装插件

    yarn add mysql xss
  2. 复用 express 项目的代码

    • controller 文件夹
    • db 文件夹
    • middleware 文件夹
    • model 文件夹
    • utils 文件夹

    复用 express 的代码后需要将其改写成 async 与 await 的语法。例如 user 的 controller

    const login = async (username, password) => {
      username = escape(username);
      // 加密密码
      password = genPassword(password);
      password = escape(password);
      const sql = `select username,realname from users where username=${username} and password=${password};`;
      const rows = await exec(sql);
      return rows[0] || {};
    };

    中间件需要将 req 与 res 合并成 ctx

    module.exports = async (ctx, next) => {
      if (ctx.session.username) {
        await next();
        return;
      }
      ctx.body = new ErrorModel("未登陆");
    };

# 开发路由 - 路由改写

大部分与 express 一致,只是写法需要使用 koa2 的写法。例如 user.js

// 路由 /api/user/login
router.post("/login", async function (ctx, next) {
  const { username, password } = ctx.request.body;
  const data = await login(username, password);
  if (data.username) {
    // 操作 Session
    ctx.session.username = data.username;
    ctx.session.realName = data.realName;
    ctx.body = new SuccessModel("登陆成功");
    return;
  } else {
    ctx.body = new ErrorModel("登陆失败");
  }
});

# 日志

koa2 的日志也需要使用 morgan,但 koa2 没有自带 morgan,因此需要自己引入一个插件。

  1. 安装插件

    yarn add koa-morgan
  2. 引入插件

    const path = require("path");
    const fs = require("fs");
    const morgan = require("koa-morgan");
  3. 编写逻辑

    // 日志记录的级别
    const ENV = process.env.NODE_ENV; // 当前运行的环境
    if (ENV !== "production") {
      app.use(
        // 开发环境 测试环境
        morgan("dev", {
          stream: process.stdout,
        })
      );
    } else {
      const logFileName = path.join(__dirname, "logs", "access.log");
      const writeStream = fs.createWriteStream(logFileName, {
        flags: "a",
      });
      app.use(
        // 线上环境
        morgan("combined", {
          stream: writeStream,
        })
      );
    }
更新于

请我喝[茶]~( ̄▽ ̄)~*

Dreamy.TZK 微信支付

微信支付

Dreamy.TZK 支付宝

支付宝