koa2实现上传文件需要中间件的帮助,由三种可以使用的,这里使用koa-body来实现
需要注意的是koa-body有一些坑需要注意:
- 位置 use的位置要在
app.use(router.routes());
之前 - 不能同时与koa-bodyparser同时使用,否则在post请求时会出现请求被拦截的情况
app.ts:
import * as koaBody from 'koa-body';
import * as Router from 'koa-router';
import AppRoutes from './routes';
const router = new Router();
// 相当于注册每一个路由,在路由文件里规定路径和方法
AppRoutes.forEach(route => router[route.method](route.path, route.action));
// 上传需要配置的中间件 引入位置讲究,且与bodyparser冲突
app.use(koaBody({
multipart: true,
formidable: {
uploadDir: path.join(__dirname, 'public/upload/'), // 设置文件上传目录
maxFileSize: 500 * 1024 * 1024, // 设置上传文件大小最大限制,默认5M
},
}));
app.use(router.routes());
app.use(router.allowedMethods());
上传逻辑部分:
export const uploadFile = async (ctx, next) => {
// 上传多个文件
const uId = 2;
const req = ctx.request.body;
const file = ctx.request.files.item; // 获取上传文件
// console.log(file);
// 创建可读流
const reader = fs.createReadStream(file.path);
const filePath = path.resolve(`src/public/upload/${file.name}`);
// 生成hash
const fsHash = crypto.createHash('md5');
const buffer = fs.readFileSync(file.path);
fsHash.update(buffer);
const fileHash = fsHash.digest('hex');
console.log('文件的MD5是:%s', fileHash);
// hash未重复时才添加
await fileModel.findOrCreate({
where: {
fileHash,
},
defaults: {
proId: req.projectId,
fileName,
filePath,
fileCreateTime: new Date(),
fileHash,
},
})
.spread((files, created) => {
console.log('文件recur是:');
console.log(created);
if (created) { // true为添加成功
// 创建可写流
const upStream = fs.createWriteStream(filePath);
// 可读流通过管道写入可写流
reader.pipe(upStream);
/* 同步读取文件,会产生阻塞 */
return ctx.body = { code: 200, msg: '上传成功!' };
} // false已经存在
return ctx.body = { code: 403, msg: '文件重复' };
});
};
删除文件逻辑部分:
/* 删除文件---根据file_id */
export const deleteSomeFile = async (ctx, next) => {
const uId = 2;
const req = ctx.request.query;
/* 先找到这个文件的project_id和file_type不用前端传值了 */
const del = await fileModel.findOne({
// 查找
where: { fileId: req.file_id },
});
/* 删除数据库中对应file_id的文件 */
await fileModel.destroy({
where: {
fileId,
},
attributes: [ 'proId' ],
});
console.log(del);
// 注意 删除时要把文件真的删除 不仅只是从数据库里删除
const filePath = path.resolve(`src/public/upload/${del.fileName}`);
deleteRecursive(filePath);
/* 删除后返回当前文件列表 */
const data = await dispalyList(del.proId);
return ctx.body = { retcode: 0, result: { data, msg: 'success' } };
};
// 判断文件是否存在再删除
const deleteRecursive = (url: string) => {
// 判断给定的路径是否存在
if (fs.existsSync(url)) {
fs.unlinkSync(url);
} else {
console.log('给定的路径不存在,请给出正确的路径');
}
};