使用 busboy 解析 multipart/form-data,添加 preservePath 选项以保留文件路径

This commit is contained in:
2025-12-21 13:48:21 +08:00
parent 8a633feb4f
commit 5e43c5fc4c
5 changed files with 11 additions and 10 deletions

View File

@@ -20,7 +20,7 @@ router.post('/api/micro-app/upload', async (req, res) => {
if (!tokenUser) return; if (!tokenUser) return;
// 使用 busboy 解析 multipart/form-data // 使用 busboy 解析 multipart/form-data
const busboy = Busboy({ headers: req.headers }); const busboy = Busboy({ headers: req.headers, preservePath: true });
const fields: any = {}; const fields: any = {};
let file: any = null; let file: any = null;
let filePromise: Promise<void> | null = null; let filePromise: Promise<void> | null = null;
@@ -33,7 +33,7 @@ router.post('/api/micro-app/upload', async (req, res) => {
busboy.on('file', (fieldname, fileStream, info) => { busboy.on('file', (fieldname, fileStream, info) => {
const { filename, encoding, mimeType } = info; const { filename, encoding, mimeType } = info;
const tempPath = path.join(cacheFilePath, `${Date.now()}-${Math.random().toString(36).substring(7)}-${filename}`); const tempPath = path.join(cacheFilePath, `${Date.now()}-${Math.random().toString(36).substring(7)}`);
const writeStream = createWriteStream(tempPath); const writeStream = createWriteStream(tempPath);
const hash = crypto.createHash('md5'); const hash = crypto.createHash('md5');
let size = 0; let size = 0;

View File

@@ -28,7 +28,7 @@ router.post('/api/app/upload', async (req, res) => {
if (!tokenUser) return; if (!tokenUser) return;
// 使用 busboy 解析 multipart/form-data // 使用 busboy 解析 multipart/form-data
const busboy = Busboy({ headers: req.headers }); const busboy = Busboy({ headers: req.headers, preservePath: true });
const fields: any = {}; const fields: any = {};
const files: any = []; const files: any = [];
const filePromises: Promise<void>[] = []; const filePromises: Promise<void>[] = [];
@@ -41,7 +41,7 @@ router.post('/api/app/upload', async (req, res) => {
busboy.on('file', (fieldname, fileStream, info) => { busboy.on('file', (fieldname, fileStream, info) => {
const { filename, encoding, mimeType } = info; const { filename, encoding, mimeType } = info;
const tempPath = path.join(cacheFilePath, `${Date.now()}-${Math.random().toString(36).substring(7)}-${filename}`); const tempPath = path.join(cacheFilePath, `${Date.now()}-${Math.random().toString(36).substring(7)}`);
const writeStream = createWriteStream(tempPath); const writeStream = createWriteStream(tempPath);
const filePromise = new Promise<void>((resolve, reject) => { const filePromise = new Promise<void>((resolve, reject) => {

View File

@@ -35,7 +35,7 @@ router.post('/api/s1/resources/upload/chunk', async (req, res) => {
} }
// 使用 busboy 解析 multipart/form-data // 使用 busboy 解析 multipart/form-data
const busboy = Busboy({ headers: req.headers }); const busboy = Busboy({ headers: req.headers, preservePath: true });
const fields: any = {}; const fields: any = {};
let file: any = null; let file: any = null;
let tempPath = ''; let tempPath = '';
@@ -47,7 +47,7 @@ router.post('/api/s1/resources/upload/chunk', async (req, res) => {
busboy.on('file', (fieldname, fileStream, info) => { busboy.on('file', (fieldname, fileStream, info) => {
const { filename, encoding, mimeType } = info; const { filename, encoding, mimeType } = info;
tempPath = path.join(cacheFilePath, `${Date.now()}-${Math.random().toString(36).substring(7)}-${filename}`); tempPath = path.join(cacheFilePath, `${Date.now()}-${Math.random().toString(36).substring(7)}`);
const writeStream = createWriteStream(tempPath); const writeStream = createWriteStream(tempPath);
filePromise = new Promise<void>((resolve, reject) => { filePromise = new Promise<void>((resolve, reject) => {

View File

@@ -107,22 +107,20 @@ router.post('/api/s1/resources/upload', async (req, res) => {
const meta = parseIfJson(url.searchParams.get('meta')); const meta = parseIfJson(url.searchParams.get('meta'));
const noCheckAppFiles = !!url.searchParams.get('noCheckAppFiles'); const noCheckAppFiles = !!url.searchParams.get('noCheckAppFiles');
// 使用 busboy 解析 multipart/form-data // 使用 busboy 解析 multipart/form-data
const busboy = Busboy({ headers: req.headers }); const busboy = Busboy({ headers: req.headers, preservePath: true });
const fields: any = {}; const fields: any = {};
const files: any[] = []; const files: any[] = [];
const filePromises: Promise<void>[] = []; const filePromises: Promise<void>[] = [];
let bytesReceived = 0; let bytesReceived = 0;
let bytesExpected = parseInt(req.headers['content-length'] || '0'); let bytesExpected = parseInt(req.headers['content-length'] || '0');
busboy.on('field', (fieldname, value) => { busboy.on('field', (fieldname, value) => {
fields[fieldname] = value; fields[fieldname] = value;
}); });
busboy.on('file', (fieldname, fileStream, info) => { busboy.on('file', (fieldname, fileStream, info) => {
const { filename, encoding, mimeType } = info; const { filename, encoding, mimeType } = info;
const tempPath = path.join(cacheFilePath, `${Date.now()}-${Math.random().toString(36).substring(7)}-${filename}`); const tempPath = path.join(cacheFilePath, `${Date.now()}-${Math.random().toString(36).substring(7)}`);
const writeStream = createWriteStream(tempPath); const writeStream = createWriteStream(tempPath);
const filePromise = new Promise<void>((resolve, reject) => { const filePromise = new Promise<void>((resolve, reject) => {
fileStream.on('data', (chunk) => { fileStream.on('data', (chunk) => {
bytesReceived += chunk.length; bytesReceived += chunk.length;

3
src/utils/sleep.ts Normal file
View File

@@ -0,0 +1,3 @@
export const sleep = (ms: number = 1000) => {
return new Promise((resolve) => setTimeout(resolve, ms));
}