更新依赖项,使用 Busboy 替代 formidable 处理文件上传,优化上传逻辑,改进权限检查
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { useFileStore } from '@kevisual/use-config/file-store';
|
||||
import { checkAuth, error, router, writeEvents, getKey, getTaskId } from '../router.ts';
|
||||
import { IncomingForm } from 'formidable';
|
||||
import Busboy from 'busboy';
|
||||
import { app, oss } from '@/app.ts';
|
||||
|
||||
import { getContentType } from '@/utils/get-content-type.ts';
|
||||
@@ -8,6 +8,9 @@ import { User } from '@/models/user.ts';
|
||||
import fs from 'fs';
|
||||
import { ConfigModel } from '@/routes/config/models/model.ts';
|
||||
import { validateDirectory } from './util.ts';
|
||||
import path from 'path';
|
||||
import { createWriteStream } from 'fs';
|
||||
import { pipeBusboy } from '@/modules/fm-manager/index.ts';
|
||||
|
||||
const cacheFilePath = useFileStore('cache-file', { needExists: true });
|
||||
|
||||
@@ -23,35 +26,70 @@ router.post('/api/s1/resources/upload/chunk', async (req, res) => {
|
||||
const url = new URL(req.url || '', 'http://localhost');
|
||||
const share = !!url.searchParams.get('public');
|
||||
const noCheckAppFiles = !!url.searchParams.get('noCheckAppFiles');
|
||||
// 使用 formidable 解析 multipart/form-data
|
||||
const form = new IncomingForm({
|
||||
multiples: false, // 改为单文件上传
|
||||
uploadDir: cacheFilePath, // 上传文件存储目录
|
||||
allowEmptyFiles: true, // 允许空
|
||||
minFileSize: 0, // 最小文件大小
|
||||
createDirsFromUploads: false, // 根据上传的文件夹结构创建目录
|
||||
keepExtensions: true, // 保留文件拓展名
|
||||
hashAlgorithm: 'md5', // 文件哈希算法
|
||||
});
|
||||
|
||||
const taskId = getTaskId(req);
|
||||
const finalFilePath = `${cacheFilePath}/${taskId}`;
|
||||
if (!taskId) {
|
||||
res.end(error('taskId is required'));
|
||||
return;
|
||||
}
|
||||
// 解析上传的文件
|
||||
form.parse(req, async (err, fields, files) => {
|
||||
const file = Array.isArray(files.file) ? files.file[0] : files.file;
|
||||
|
||||
// 使用 busboy 解析 multipart/form-data
|
||||
const busboy = Busboy({ headers: req.headers });
|
||||
const fields: any = {};
|
||||
let file: any = null;
|
||||
let tempPath = '';
|
||||
let filePromise: Promise<void> | null = null;
|
||||
|
||||
busboy.on('field', (fieldname, value) => {
|
||||
fields[fieldname] = value;
|
||||
});
|
||||
|
||||
busboy.on('file', (fieldname, fileStream, info) => {
|
||||
const { filename, encoding, mimeType } = info;
|
||||
tempPath = path.join(cacheFilePath, `${Date.now()}-${Math.random().toString(36).substring(7)}-${filename}`);
|
||||
const writeStream = createWriteStream(tempPath);
|
||||
|
||||
filePromise = new Promise<void>((resolve, reject) => {
|
||||
fileStream.pipe(writeStream);
|
||||
|
||||
writeStream.on('finish', () => {
|
||||
file = {
|
||||
filepath: tempPath,
|
||||
originalFilename: filename,
|
||||
mimetype: mimeType,
|
||||
};
|
||||
resolve();
|
||||
});
|
||||
|
||||
writeStream.on('error', (err) => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
busboy.on('finish', async () => {
|
||||
// 等待文件写入完成
|
||||
if (filePromise) {
|
||||
try {
|
||||
await filePromise;
|
||||
} catch (err) {
|
||||
console.error(`File write error: ${err.message}`);
|
||||
res.end(error(`File write error: ${err.message}`));
|
||||
return;
|
||||
}
|
||||
}
|
||||
const clearFiles = () => {
|
||||
if (file) {
|
||||
fs.unlinkSync(file.filepath);
|
||||
if (tempPath && fs.existsSync(tempPath)) {
|
||||
fs.unlinkSync(tempPath);
|
||||
}
|
||||
if (fs.existsSync(finalFilePath)) {
|
||||
fs.unlinkSync(finalFilePath);
|
||||
}
|
||||
};
|
||||
|
||||
if (err) {
|
||||
res.end(error(`Upload error: ${err.message}`));
|
||||
clearFiles();
|
||||
if (!file) {
|
||||
res.end(error('No file uploaded'));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -69,9 +107,7 @@ router.post('/api/s1/resources/upload/chunk', async (req, res) => {
|
||||
clearFiles();
|
||||
return;
|
||||
}
|
||||
const tempPath = file.filepath;
|
||||
const relativePath = file.originalFilename;
|
||||
// Append chunk to the final file
|
||||
|
||||
const writeStream = fs.createWriteStream(finalFilePath, { flags: 'a' });
|
||||
const readStream = fs.createReadStream(tempPath);
|
||||
@@ -195,4 +231,6 @@ router.post('/api/s1/resources/upload/chunk', async (req, res) => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
pipeBusboy(req, res, busboy);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user