const path = require("path");
const fs = require("fs");
const uuid = require("uuid/v1"); // 生成随机串
const app = new Koa();
// 将 koa-better-body 中间件从 koa 1.0 转化成 koa 2.0,并使用中间件
app.use(convert(betterBody({
uploadDir: path.resolve(__dirname, "upload")
})));
app.use(async (ctx, next) => {
if (ctx.path === "/" && ctx.method === "POST") {
// 使用中间件后 ctx.request.fields 属性自动加上了 post 请求的文件数据
console.log(ctx.request.fields);
// 将文件重命名
let imgPath = ctx.request.fields.avatar[0].path;
let newPath = path.resolve(__dirname, uuid());
fs.rename(imgPath, newPath);
}
});
app.listen(3000);
上面代码中 koa-better-body 的主要功能就是将表单上传的文件存入本地指定的文件夹下,并将文件流对象挂在了 ctx.request.fields 属性上,我们接下来就模拟 koa-better-body 的功能实现一版基于 Koa 2.x 处理文件上传的中间件。
文件:my-koa-better-body.js
const fs = require("fs");
const uuid = require("uuid/v1");
const path = require("path");// 给 Buffer 扩展 split 方法预备后面使用
Buffer.prototype.split = function (sep) {
let len = Buffer.from(sep).length; // 分隔符所占的字节数
let result = []; // 返回的数组
let start = 0; // 查找 Buffer 的起始位置
let offset = 0; // 偏移量
// 循环查找分隔符
while ((offset = this.indexOf(sep, start)) !== -1) {
// 将分隔符之前的部分截取出来存入
result.push(this.slice(start, offset));
start = offset + len;
}
// 处理剩下的部分
result.push(this.slice(start));
// 返回结果
return result;
}
module.exports = function (options) {
return async (ctx, next) => {
await new Promise((resolve, reject) => {
let dataArr = []; // 存储读取的数据
// 读取数据
ctx.req.on("data", data => dataArr.push(data));
ctx.req.on("end", () => {
// 取到请求体每段的分割线字符串
let bondery = `--${ctx.get("content-Type").split("=")[1]}`;
// 获取不同系统的换行符
let lineBreak = process.platform === "win32" ? "rn" : "n";
// 非文件类型数据的最终返回结果
let fields = {};
// 分隔的 buffer 去掉没用的头和尾即开头的 '' 和末尾的 '--'
dataArr = dataArr.split(bondery).slice(1, -1);
// 循环处理 dataArr 中每一段 Buffer 的内容
dataArr.forEach(lines => {
// 对于普通值,信息由包含键名的行 + 两个换行 + 数据值 + 换行组成
// 对于文件,信息由包含 filename 的行 + 两个换行 + 文件内容 + 换行组成









