Skip to content
大纲

中间件

koa-logger

日志记录,建议为顶部中间件

文档: https://github.com/koajs/logger

shell
npm install koa-logger
js
const logger = require("koa-logger");
const Koa = require("koa");

const app = new Koa();
app.use(logger());
js
app.use(
  logger((str, args) => {
    // str 日志内容,默认是 ANSI 编码的,可以通过 `strip-ansi` 进行还原
    // args 格式 [format, method, url, status, time, length]
    // 自定义日志处理方式,默认为 process.stdout (即 console.log)
  })
);
js
// strip-regex 源码
function ansiRegex({ onlyFirst = false } = {}) {
  const pattern = [
    "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
    "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))",
  ].join("|");
  return new RegExp(pattern, onlyFirst ? undefined : "g");
}

// strip-ansi 源码
function stripAnsi(string) {
  if (typeof string !== "string") {
    throw new TypeError(`Expected a \`string\`, got \`${typeof string}\``);
  }
  return string.replace(ansiRegex(), "");
}

send & static

文档: https://github.com/koajs/send 文档: https://github.com/koajs/static

说明 koa-static 是对 koa-send 的一层封装,增加了 header 判断和默认 index 配置

shell
npm i koa-static
js
const static = require("koa-static");
const Koa = require("koa");
const app = new Koa();

// or use absolute paths
app.use(static("public"));
js
format如果不是false(默认为true),则格式化为静态文件服务器提供服务的路径,并且目录不需要尾部斜杠,这样您就可以同时执行/directory和/directory/
setHeaders在响应中设置自定义标头的功能。
extensions当 URL 中没有扩展名时,尝试匹配传递数组中的扩展名以搜索文件。首先找到的是服务。(默认为false)
const options = {
  maxage: 0,         // 浏览器缓存,单位毫秒
  immutable: false,  // 资源是否不可变
  hidden: false,     // 允许传输隐藏文件
  root: '',          // 根目录
  index: undefined,  // 索引文件名称
  gzip: true,        // 当客户端支持且请求带有 .gz 扩展名文件时尝试提供 gzip 版本
  brotli: true,      // 当客户端支持且请求带有 .br 扩展名文件时创世提供 brotli 版本
  format: true,     // 文件路径格式化(置为false可以同时区分 `/xxx/` 和 `/xxx` 格式)
  setHeaders: (res, path, stats) => any // 自定义 header
  extensions: false, // 扩展名
}

// koa-static 额外配置
const staticExt = {
  defer: false,	// 延迟执行,若为 true, 则先执行 `await next()`
}

koa-session

shell
npm i koa-session --save
js
import Koa from "koa";
import session from "koa-session";

const app = new Koa();

const congif = {
  key: "it is a cookie key",
  maxAge: 7 * 24 * 3600 * 1000, // 7天
  overwrite: true, // 是否可以重写
  httpOnly: true, // 是否httpOnly
  signed: true, // 是否签名
  rolling: false, // 是否每一个响应都传递cookie
};

app.keys = ["fgsdfgsd", "dgadgv", "dgage"]; //随便设置keys
app.use(session(config, app));

/**
 * - 设置 `ctx.session[key] = val`
 * - 获取 `ctx.session[key]`
 * - 删除 `delete ctx.session[key]`
 */

jwt

文档: https://github.com/koajs/jwt

js
// 前端
let state = {
  token: "",
};

// 登录获取 token
async function login() {
  const result = await fetch("/login", { method: "POST" }).then(res =>
    res.json()
  );
  state.token = result.token;
}

async function other() {
  const result = await fetch("/other", {
    method: "POST",
    headers: {
      authorization: "Bearer " + state.token,
    },
  }).then(res => res.json());
}
js
// 后端
const Koa = require("koa");
const static = require("koa-static");
const Router = require("koa-router");
const koaJwt = require("koa-jwt");
const jwt = require("jsonwebtoken");

const app = new App();

const router = new Router();
const secret = "12345";

router.post("/login", ctx => {
  const token = jwt.sign({ user: "ZzzzNeko" }, secret, { expiresIn: "1d" });
  ctx.body = { token };
});

router.post("/other", ctx => {
  ctx.body = ctx.state.user;
});

app.use(static("publick"));
app.use(koaJwt({ secret }).unless({ path: /^login/ }));
app.use(router.routes());
app.use(router.allowedMethods());

app.listen(3000);

说明

  • login 中对注册信息加密后生成 token
  • ctx.state.user 为对应 token 的注册信息

koa-body

文档: https://github.com/koajs/koa-body 文档: https://github.com/koajs/bodyparser 说明:

  • koa-body 较 bodyparser 功能更全,且支持文件处理
  • koa-body 可作为 koa-router 的中间件使用
shell
npm install koa-body
js
const Koa = require("koa");
const koaBody = require("koa-body");

const app = new Koa();
app.use(koaBody());
app.use(ctx => {
  console.log("请求内容为: ", ctx.request.body);
  console.log("上传文件为: ", ctx.request.files);
});

koa-router

shell
npm i koa-router --save
js
const Koa = require("koa");
const Router = require("koa-router");
const app = new Koa();

const router = new Router();

router.get("/hello", (ctx, next) => {
  ctx.body = "hello man";
});

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

app.listen(80);

compress

文档: https://github.com/koajs/compress

js
const compress = require("koa-compress");
const Koa = require("koa");

const app = new Koa();
app.use(
  compress({
    filter(content_type) {
      return /text/i.test(content_type);
    },
    threshold: 2048,
    gzip: {
      flush: require("zlib").constants.Z_SYNC_FLUSH,
    },
    deflate: {
      flush: require("zlib").constants.Z_SYNC_FLUSH,
    },
    br: false, // disable brotli
  })
);
js
interface Options {
  filter: (mimeType: string) => boolean
  threshold: string | number
  encoding: {}
  br: boolean // brotli 压缩
  defaultEncoding: string
}

conditional-get & etag

shell
npm install koa-conditional-get koa-etag
js
const conditional = require("koa-conditional-get");
const etag = require("koa-etag");
const Koa = require("koa");
const app = new Koa();

// use it upstream from etag so
// that they are present
app.use(conditional());

// add etags
app.use(etag());

koa-cash

shell
npm i koa-cash
npm i -D @types/koa-cash

cors

shell
npm install @koa/cors
js
const Koa = require("koa");
const cors = require("@koa/cors");

const app = new Koa();
app.use(cors());
js
interface Options {
  origin: string | ctx => string  // 默认为请求头 origin
  allowMethods: string | string[] // 默认 'GET,HEAD,PUT,POST,DELETE,PATCH'
  exposeHeaders: string | string[] // 配置 Access-Control-Expose-Headers
  allowHeaders: string | string[]  // 配置 Access-Control-Allow-Headers
  maxAge: string | number          // 配置 Access-Control-Max-Age, 单位秒
  credentials: boolean | ctx => boolean // 配置 Access-Control-Allow-Credentials, 默认 false
  keepHeadersOnError: boolean // 抛出异常时,添加一个头到 err.header 中
  secureContext: boolean      // 设置 `Cross-Origin-Opener-Policy` & `Cross-Origin-Embedder-Policy` 头,默认 false
  privateNetworkAccess: boolean // 默认 false,通过返回 `Access-Control-Allow-Private-Network` 处理 `Access-Control-Request-Private-Network` 请求
}

csrf

文档: https://github.com/koajs/csrf

shell
npm i koa-csrf
js
const CSRF = require("koa-csrf");
app.use(new CSRF());

koa-ratelimit

访问频次 限制

文档: https://github.com/koajs/ratelimit

shell
npm install koa-ratelimit
js
// 通过 redis
const Koa = require("koa");
const ratelimit = require("koa-ratelimit");
const Redis = require("ioredis");
const app = new Koa();

app.use(
  ratelimit({
    driver: "redis",
    db: new Redis(),
    duration: 60000,
    errorMessage: "Sometimes You Just Have to Slow Down.",
    id: ctx => ctx.ip,
    headers: {
      remaining: "Rate-Limit-Remaining",
      reset: "Rate-Limit-Reset",
      total: "Rate-Limit-Total",
    },
    max: 100,
    disableHeader: false,
    whitelist: ctx => {
      // some logic that returns a boolean
    },
    blacklist: ctx => {
      // some logic that returns a boolean
    },
  })
);
js
// 本地内存
const Koa = require("koa");
const ratelimit = require("koa-ratelimit");
const app = new Koa();

// apply rate limit
const db = new Map();

app.use(
  ratelimit({
    driver: "memory",
    db: db,
    duration: 60000,
    errorMessage: "Sometimes You Just Have to Slow Down.",
    id: ctx => ctx.ip,
    headers: {
      remaining: "Rate-Limit-Remaining",
      reset: "Rate-Limit-Reset",
      total: "Rate-Limit-Total",
    },
    max: 100,
    disableHeader: false,
    whitelist: ctx => {
      // some logic that returns a boolean
    },
    blacklist: ctx => {
      // some logic that returns a boolean
    },
  })
);
js
interface Options {
  driver: 'redis' | 'redis'
  db:
}

静态文件服务

文档:

shell
pnpm i koa2-serve-index
pnpm i koa-serve-static
js
const Koa = require("koa");
const serveIndex = require("koa2-serve-index");
const serveStatic = require("koa-serve-static");

const app = new Koa();

app.use(serveIndex("public", { icons: true, view: "details" }));
app.use(serveStatic("public"));

说明

  • koa2-serve-index 用来映射目录和文件
  • koa-serve-static 可以换成 koa-static 用于访问文件