Node 小册 | Koa 入门 🍙

766 阅读2分钟

本文仓库地址 github.com/LuckyChou71…

官网 koajs.com/

Koa

koa 支持 async 和 await 的用法

这就意味着在 koa 中可以抛去 express 中回调函数的写法 用一种更优雅的方式来解决异步场景

基本使用

与 express 不同的是 koa 导出的不是函数 而是一个名为 Application 的对象

Screen Shot 2022-03-25 at 10.53.52.png

所以在使用上我们只需要 new 一个实例即可 其他用法和 Express 基本相似

const Koa = require('koa');

const app = new Koa();

app.listen(3000, () => {
  console.log('server start...');
});

Koa 本身十分纯净 几乎大部分的功能都是通过插件的方式来实现

路由

这里我们借助第三方模块 koa-router

新建一个 user.js 的路由模块

Koa 将 express 中的 request 和 response 都合成到了上下文对象 context 中 简写为 ctx

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

const userRouter = new Router({ prefix: '/user' });

userRouter.get('/home', (ctx, next) => {
  ctx.body = 'welcome~~';
});

userRouter.post('/login', (ctx, next) => {
  ctx.body = 'login...';
});

module.exports = userRouter;

然后在 index 中引入 user.js

const Koa = require('koa');

const userRouter = require('./router/user');

const app = new Koa();

app.use(userRouter.routes());

app.listen(3000, () => {
  console.log('server start...');
});

然后访问 http://localhost:3000/user/home 我们就可以看到

Screen Shot 2022-03-14 at 23.26.24.png

处理请求

koa 中需要引入 koa-bodyparser 来解析 json 和 urlencoded

const Koa = require("koa");
const Router = require("koa-router");
const bodyParser = require("koa-bodyparser");

const app = new Koa();
const router = new Router();

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

// 解析query
router.get("/query", (ctx, next) => {
  console.log(ctx.request.query);
});

// 解析params
router.get("/params/:id", (ctx, next) => {
  console.log(ctx.request.params);
});

// 解析urlencoded
router.post("/urlencoded", (ctx, next) => {
  console.log(ctx.request.body);
});

// 解析json
router.post("/json", (ctx, next) => {
  console.log(ctx.request.body);
});

app.listen(8080, () => {
  console.log("start");
});
  • query

Screen Shot 2022-03-14 at 23.31.43.png

  • params

Screen Shot 2022-03-14 at 23.32.32.png

  • urlencoded

Screen Shot 2022-03-14 at 23.33.32.png

  • json

Screen Shot 2022-03-14 at 23.36.08.png

注意 koa-bodyparser 中间件需要最先被使用

异步处理

Koa 的中间件支持 async / await 的语法 例如下面这个demo就可以正常拼接ABC输出

const express = require('express');

const app = express();

const middlewareA = (req, res, next) => {
  req.message = '';
  req.message += 'A';
  next();
  res.end(req.message);
};

const middlewareB = async (req, res, next) => {
  req.message += await Promise.resolve('B');
  await next();
};

const middlewareC = (req, res, next) => {
  req.message += 'C';
  next();
};

app.use(middlewareA);
app.use(middlewareB);
app.use(middlewareC);

app.listen(3000, () => {
  console.log('server start...');
});

访问 http://localhost:3000 就可以看到

Screen Shot 2022-03-25 at 11.08.11.png

出现 Not Found 是因为我们并未配置路有 但是可以后面的ABC已经正确输出了

洋葱模型

洋葱模型其实不是什么高大尚的概念 先来看一个demo

const Koa = require('koa');

const app = new Koa();

const middlewareA = (ctx, next) => {
  console.log('middlewareA');
  next();
  console.log('middlewareA');
};

const middlewareB = (ctx, next) => {
  console.log('middlewareB');
  next();
  console.log('middlewareB');
};

const middlewareC = (ctx, next) => {
  console.log('middlewareC');
  next();
  console.log('middlewareC');
};

app.use(middlewareA);
app.use(middlewareB);
app.use(middlewareC);

app.listen(3000, () => {
  console.log('server start');
});

访问 3000 端口 我们可以看到 控制台输出

middlewareA
middlewareB
middlewareC
middlewareC
middlewareB
middlewareA

通过下图我们不难发现 所有中间件都会被 request 访问两次 就像剥洋葱一样 这就是洋葱模型

注意 Express 同样也是洋葱模型

express 对比 koa

  • express 是完整和强大的,其中帮助我们内置了非常多好用的功能;

  • koa 是简洁和自由的,它只包含最核心的功能,并不会对我们使用其他中间件进行任何的限制。 甚至是在 app 中连最基本的 get、post 都没有给我们提供;我们需要通过自己或者路由来判断请求方式或者其他功能