中间件
koa-logger
日志记录,建议为顶部中间件
文档: https://github.com/koajs/logger
shell
npm install koa-loggerjs
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-staticjs
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 --savejs
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-bodyjs
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 --savejs
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-etagjs
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-cashcors
shell
npm install @koa/corsjs
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-csrfjs
const CSRF = require("koa-csrf");
app.use(new CSRF());koa-ratelimit
访问频次 限制
文档: https://github.com/koajs/ratelimit
shell
npm install koa-ratelimitjs
// 通过 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:
}静态文件服务
文档:
- server-index: https://github.com/expressjs/serve-index
- server-static: https://github.com/expressjs/serve-static
shell
pnpm i koa2-serve-index
pnpm i koa-serve-staticjs
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用于访问文件