我正在开发一个 Node.js 应用程序,我需要解析和保存通过 HTTP 请求发送的多部分表单数据。我正在使用内置的 http 模块来处理请求,并且我已成功解析多部分表单数据。但是,我在尝试在本地保存文件时遇到了困难。 这是负责解析多部分表单数据并尝试保存文件的函数:
const fs = require('fs');
function parseMultipartFormData(req) {
let body = req.body;
const boundary = body.split(/\r?\n|\r/, 1)[0];
body = body.split(boundary);
body.shift();
body.pop();
let parsedData = {};
for (let part of body) {
part = part.trim();
if (part.includes("filename")) {
const fileRegex = /name="(.+)"; filename="(.+)"\r?\nContent-Type: (\w+\/\w+)(?:\r?\n)*([\s\S]*)/;
const match = fileRegex.exec(part);
if (match) {
parsedData[match[1]] = {
filename: match[2],
contentType: match[3],
contentData: match[4],
};
}
} else {
part = part.replace(/\r?\n|\r/g, "");
const regex = /name="(.+)"(.+)/;
const match = regex.exec(part);
if (match) {
parsedData[match[1]] = match[2];
}
}
}
// Write file if productImage exists
if (parsedData.productImage && parsedData.productImage.contentData) {
const imageData = parsedData.productImage.contentData;
const filename = parsedData.productImage.filename;
fs.writeFile(filename, imageData, "binary", (err) => {
if (err) {
console.error('Error saving image:', err);
} else {
console.log('Image saved successfully.');
}
});
}
return parsedData;
}
我已经故意避免使用 multer 或任何类似的第三方库来完成此任务。
我注意到文件没有正确保存,并且我不确定如何正确处理文件数据。任何人都可以提供有关如何在这种情况下正确处理和保存文件的指导吗?
此外,这是解析后的表单数据处理后的样子:
{
"productName": "Carolyn Jordan",
"productDescription": "Eligendi enim conseq",
"productPrice": "82",
"productImage": {
"filename": "logoWhiteBgSocial.png",
"contentType": "image/png",
"contentData": "�PNG IHDRLL�� pHYs��sRGB���gAMA���a8zIDATx���uTW����=��vG@w�� ... (truncated)"
}
}
我试图查看数据是否以 gzip、defalte...等方式编码或压缩,但我在请求标头中找不到任何有用的信息。
// 'express-form-data' - принимает данные которые прилетают из формы в формате FormData и делает для нас понятными.
let parse_formdata = require('express-form-data'); // Модуль парсит данные formDate которые прилетели из формы.
let options_parse_formdata = {
uploadDir: os.tmpdir(), // Означает отчистить папку temp в компьютере после того как загрузим файл.
autoClean: true // Выставляем на true, то есть удалять, потому что по умолчанию стоит false.
};
// Это всё ещё настройки express-form-data чтобы налету парсить данные с форм.
app.use(parse_formdata.parse(options_parse_formdata)); // Анализ данных с помощью connect-multiparty.
app.use(parse_formdata.format()); // Удаляем файлы если они весят 0 байт.
app.use(parse_formdata.stream()); // Изменить объекты файла на fs.ReadStream.
app.use(parse_formdata.union()); // Объеденение тела и файлов.
app.post('/add', async function(req, res, next){
// Создаём имя файла для будущего изображения. А путь до изображения будет меняться. Сначала мы сохраняем по адресу: './static/images/' + file_name, а в базу данных заноисм как './images/' + file_name потому что когда выбираем изображение после регистрации мы не пишем папку static.
let file_name = new Date().getTime().toString() + (Math.random()*900+100).toFixed(0) + '.png';
let read_stream = fs.createReadStream(req.body.avatar.path); // Создём источник, откуда подгружаем данные из файла.
let write_stream = fs.createWriteStream('./static/images/' + file_name); // Создаём новый файл, записываетель и передаём путь куда надо сохранить файл и имя будущего файла.
read_stream.pipe(write_stream); // Теперь мы читаем данные о файле из read_stream в новый файл write_stream. Так у нас создаётся новый файл.
// Вешаем событие для того чтобы узнать когда данные из источника перетекут в новый файл записываетель.
write_stream.on('finish', async () => { // После того как изображение будет записано на сервер, можем показать уведосление.
console.log('Файл сохранён на сервер.');
});
});
// Модуль 'multer' не используйте! Потому что если у вас будет валидатор, то 'multer' сначала сохранить файл, распарсит данные, а уже только потом будет проверять имя, фамилию.