写在开头
koa2 一个由 Express
原班人马打造的,基于 Node
平台的下一代 Web 开发框架。
它属于前端老熟客了,这里就不过多介绍。
本章主要讨论一下如何编写其中间件(middleware
)并编写一个"接口必填参数校验"的中间件。
初始化koa2项目🏗️
为了方便快速创建 koa2
项目,我们可以全局安装一下 koa2
的脚手架 koa-generator
javascript
npm install -g koa-generator
它等同于 vue
的 cli
,react
的 react-create-app
这些脚手架。
测试安装是否成功:
javascript
koa2 -V
注意命令是 koa2
哦,能正常看到版本号就说明安装成功了。
初始化项目:
javascript
koa2 your-project-name
能得到这么一个项目目录:

安装项目依赖:
javascript
npm install
启动项目:
javascript
npm run start
// or
npm run dev
dev
命令具有热更新的效果,修改项目代码会及时更新,而热更新是通过 nodemon 包来实现的。
项目启动后,默认端口是 3000
。

基于脚手架创建的项目,默认在 routes
文件夹中帮我们生成了一些接口,你可以访问以下这些路径测试看看:
javascript
http://localhost:3000/
http://localhost:3000/string
http://localhost:3000/json
http://localhost:3000/users
http://localhost:3000/users/bar
中间件语法🚀
准备完项目后,就可以来尝试编写 koa2
的中间件了。
那么,什么是中间件呢?
在 koa2
框架中,你可以将HTTP请求想象成一条水流,而中间件则像是连接在这条水流上的各种管道。每个中间件都会对这条水流(即HTTP请求和响应)进行处理和改写。

中间件本质是一个异步函数,它可以访问请求对象、响应对象和下一个中间件函数。
语法也挺简单的,写完异步函数往 app.use
注册一下就行了。
javascript
const middleware = async (ctx, next) => {
// TODO: 你需要处理逻辑,从ctx能获取到很多信息,如参数列表
// 抛给下一个中间件
await next();
};
app.use(middleware);
注意,中间件的注册有顺序先后的❗
必填参数校验的中间件🎯
了解中间件基本语法后,我们就可以来编写自己的中间件了,这次要写的中间件主要是针对参数校验的。
很多时候,前端拿到后端开发的接口后,经常能看到一些接口参数被标记成必填,本次要写的中间件就是为了完成这个功能。
在项目根目录下创建 middleware
文件夹,用于存放各种中间件。
创建 middleware/requiredParams.js
文件,用于编写本次的中间件,功能不复杂,咱们贴上来直接瞧瞧。
javascript
module.exports = (options = {}) => {
return async (ctx, next) => {
/**
* @name 用于校验接口必填参数的中间件
* @param { string | Array<string> | Object } requiredParams
* @return { boolean }
*/
ctx.requiredParams = (requiredParams) => {
// 获取接口的请求方式
let method = ctx.method;
// 获取接口的参数列表
let params = method.toLocaleUpperCase() === "GET" ? ctx.query : ctx.request.body;
// 接口需要检验必填参数
if (!isEmpty(requiredParams)) {
// 只有一个必填参数需要验证
if (typeof requiredParams === "string") {
if (!(requiredParams in params) || (!params[requiredParams] && params[requiredParams] !== 0)) {
ctx.body = "字段" + requiredParams + "为必填";
return true;
}
}
// 有多个参数需要验证必填
if (Array.isArray(requiredParams)) {
let paramsKeys = Object.keys(params);
const message = [];
for (let i = 0; i < requiredParams.length; i++) {
if (!paramsKeys.includes(requiredParams[i]) || (!params[requiredParams[i]] && params[requiredParams[i]] !== 0)) {
message.push("字段" + requiredParams[i] + "为必填");
}
}
if (message.length > 0) {
ctx.body = message.join("\n");
return true;
}
}
// 支持自定义提示语,key为参数名,value为自定义的提示语
if (Object.prototype.toString.call(requiredParams) === "[object Object]") {
const message = [];
for (let key in requiredParams) {
if (!(key in params) || (!params[key] && params[key] !== 0)) {
if (requiredParams[key]) {
message.push(requiredParams[key]);
} else {
message.push("字段" + key + "为必填");
}
}
}
if (message.length > 0) {
ctx.body = message.join("\n");
return true;
}
}
}
};
await next();
};
};
/**
* @name 检验非空的工具函数
* @param { * } val 检验目标
* @return { boolean }
*/
function isEmpty(val) {
if (val === 0) return false;
// null or undefined
if (val == null) return true;
if (typeof val === "boolean") return false;
if (typeof val === "number") return !val;
if (val instanceof Error) return val.message === "";
switch (Object.prototype.toString.call(val)) {
// String or Array
case "[object String]":
case "[object Array]":
return !val.length;
// Map or Set or File
case "[object File]":
case "[object Map]":
case "[object Set]": {
return !val.size;
}
// Plain Object
case "[object Object]": {
return !Object.keys(val).length;
}
}
return false;
}
在 app.js
文件中注册:
js
...
const requiredParams = require("./middleware/requiredParams.js");
...
app.use(json());
app.use(logger());
app.use(require("koa-static")(__dirname + "/public"));
// 注册
app.use(requiredParams());
中间件代码都写有注释,可以仔细看看,其主要写了三种验证形式,字符串、数组、对象,我们可以分别来看看应用的情况。
以 http://localhost:3000/users/bar
接口为例:
javascript
// routes/users.js
router.get("/bar", function (ctx, next) {
// 要求 name 参数必传
if (ctx.requiredParams("name")) return;
ctx.body = "我是bar接口";
});
效果如下:
测试多个必填参数情况:
javascript
// routes/users.js
router.get("/bar", function (ctx, next) {
// 要求 name、age、sex 参数必传
if (ctx.requiredParams(["name", "age", "sex"])) return;
ctx.body = "我是bar接口";
});
测试自定义提示语情况:
javascript
// routes/users.js
router.get("/bar", function (ctx, next) {
if (ctx.requiredParams({
name: "这个name参数一定一定要填",
age: "年龄也要填哦",
})) return;
ctx.body = "我是bar接口";
});

至此,本篇文章就写完啦,撒花撒花。

希望本文对你有所帮助,如有任何疑问,期待你的留言哦。
老样子,点赞+评论=你会了,收藏=你精通了。