Koa.js 中间件
中间件分类
狭义中间件
前言
狭义中间件的要素常见要素如下所示。
- 一切皆中间件
- 中间件内操作请求
request
- 请求拦截
- 中间件内操作响应
response
- 响应拦截
- 中间件内操作上下文
context
- 直接上下文代理,初始化实例时候挂载代理在
app.context
上 - 请求过程上下文代理,请求时候挂载代理在
ctx
上
- 直接上下文代理,初始化实例时候挂载代理在
- 大部分直接被
app.use()
加载- 注意: 初始化实例挂载代理
context
不被app.use()
- 注意: 初始化实例挂载代理
请求拦截
const Koa = require('koa');
let app = new Koa();
const middleware = async function (ctx, next) {
// 中间件 拦截请求
// 把所有请求不是 /page/ 开头的路径全部抛出500错误
const reqPath = ctx.request.path;
if (reqPath.indexOf('/page/') !== 0) {
ctx.throw(500);
}
await next();
};
const page = async function (ctx, next) {
ctx.body = `
<html>
<head></head>
<body>
<h1>${ctx.request.path}</h1>
</body>
</html>
`;
};
app.use(middleware);
app.use(page);
app.listen(3001, function () {
console.log('the demo is start at port 3001');
});
响应拦截
const Koa = require('koa');
let app = new Koa();
const middleware = async function (ctx, next) {
ctx.response.type = 'text/plain';
await next();
};
const page = async function (ctx, next) {
ctx.body = `
<html>
<head></head>
<body>
<h1>${ctx.path}</h1>
</body>
</html>
`;
};
app.use(middleware);
app.use(page);
app.listen(3001, function () {
console.log('the demo is start at port 3001');
});
context挂载代理
- 请求代理注入
- 直接被app.use
- 请求时候才有注入
- 每次请求的注入都不同
- 初始化实例(应用)代理注入
- 直接注入到app.context
- 初始化应用的时候才注入
- 只注入一次,每次请求都可以使用
请求时挂载代理context
const Koa = require('koa');
let app = new Koa();
const middleware = async function (ctx, next) {
// 中间件 代理/挂载上下文
// 把所有当前服务的进程PID,内存使用情况方法代理/挂载在ctx上
ctx.getServerInfo = function () {
function parseMem(mem = 0) {
let memVal = mem / 1024 / 1024;
memVal = memVal.toFixed(2) + 'MB';
return memVal;
}
function getMemInfo() {
let memUsage = process.memoryUsage();
let rss = parseMem(memUsage.rss);
let heapTotal = parseMem(memUsage.heapTotal);
let heapUsed = parseMem(memUsage.heapUsed);
return {
pid: process.pid,
rss,
heapTotal,
heapUsed
};
}
return getMemInfo();
};
await next();
};
const page = async function (ctx, next) {
const serverInfo = ctx.getServerInfo();
ctx.body = `
<html>
<head></head>
<body>
<p>${JSON.stringify(serverInfo)}</p>
</body>
</html>
`;
};
app.use(middleware);
app.use(page);
app.listen(3001, function () {
console.log('the demo is start at port 3001');
});
初始化实例挂载代理context
const Koa = require('koa');
let app = new Koa();
const middleware = function (app) {
// 中间件在初始化实例 把getServerInfo方法 挂载代理到上下文
app.context.getServerInfo = function () {
function parseMem(mem = 0) {
let memVal = mem / 1024 / 1024;
memVal = memVal.toFixed(2) + 'MB';
return memVal;
}
function getMemInfo() {
let memUsage = process.memoryUsage();
let rss = parseMem(memUsage.rss);
let heapTotal = parseMem(memUsage.heapTotal);
let heapUsed = parseMem(memUsage.heapUsed);
return {
pid: process.pid,
rss,
heapTotal,
heapUsed
};
}
return getMemInfo();
};
};
middleware(app);
const page = async function (ctx, next) {
const serverInfo = ctx.getServerInfo();
ctx.body = `
<html>
<head></head>
<body>
<p>${JSON.stringify(serverInfo)}</p>
</body>
</html>
`;
};
app.use(page);
app.listen(3001, function () {
console.log('the demo is start at port 3001');
});
广义中间件
前言
- 不直接提供中间件
- 通过间接方式提供了中间件,最常见的是
间接中间件
和子中间件
- 间接被
app.use()
加载 - 其他方式接入Koa切面
间接中间件
const Koa = require('koa');
let app = new Koa();
function indirectMiddleware(path, middleware) {
return async function (ctx, next) {
console.log(ctx.path === path, middleware);
if (ctx.path === path) {
await middleware(ctx, next);
} else {
await next();
}
};
}
const index = async function (ctx, next) {
ctx.body = 'this is index page';
};
const hello = async function (ctx, next) {
ctx.body = 'this is hello page';
};
const world = async function (ctx, next) {
ctx.body = 'this is world page';
};
app.use(indirectMiddleware('/', index));
app.use(indirectMiddleware('/hello', hello));
app.use(indirectMiddleware('/world', world));
app.listen(3001, () => {
console.log('the demo is start at port 3001');
});
子中间件
子中间件是广义中间件的一个最有代表场景,主要的特点有
- 初始化中间件时,内置子中间件列表
- 子中间件列表添加子中间件元素
- 子中间件列表封装成间接中间件,让后被
app.use()
加载
const Koa = require('koa');
let app = new Koa();
class Middleware {
constructor() {
this.stack = [];
}
get(path, childMiddleware) {
this.stack.push({ path, middleware: childMiddleware });
}
middlewares() {
let stack = this.stack;
return async function (ctx, next) {
let path = ctx.path;
for (let i = 0; i < stack.length; i++) {
const child = stack[i];
if (child && child.path === path && child.middleware) {
await child.middleware(ctx, next);
}
}
await next();
};
}
}
const middleware = new Middleware();
middleware.get('/page/001', async (ctx, next) => {
ctx.body = 'page 001';
});
middleware.get('/page/002', async (ctx, next) => {
ctx.body = 'page 002';
});
middleware.get('/page/003', async (ctx, next) => {
ctx.body = 'page 003';
});
app.use(middleware.middlewares());
app.listen(3001, function () {
console.log('the demo is start at port 3001');
});