Я работаю над созданием фильтра, основанного на оценке подписи файла, полученной через файловый буфер, предоставленный Multer. Я знаю, что Multer предоставляет тип MIME, но мне также нужно проверить, действительно ли файл относится к этому типу MIME, используя некоторые другие способы проверки.
По этой причине мои действия таковы:
ПРОБЛЕМА: Как только я вызываю какую-то ошибку на второй конечной точке, процесс зацикливается. Ошибка обнаружена, однако я не могу вернуть какой-либо HTTP-код в ответ на первую конечную точку!
Первая конечная точка:
/* NOTE: storeInMemory.array("files") stores in memory the files' buffer information, which
/* are needed in order to work with validating the files! */
app.post("/filesUpload", storeInMemory.array("files"), async (req, res) => {
const files = req.files;
/* this array stores the items i have to upload */
let uploadArray = [];
/* filter only the items i actually need to upload */
for (const item of files) {
/*-- some filter logic --*/
uploadArray.push(item);
}
/* create new FormData to store the actual files i have to upload -
/* as multer works with http a new formdata has to be created, so i can make a call to another endpoint */
let form = new FormData();
form.append("someData", req.body["someData"]);
/* append the files to the form i'll use to upload later */
uploadArray.forEach((item) => {
form.append("files", item.buffer, item.originalname);
});
try {
const postUrl = process.env.MY_URL + "/upload";
const myHeaders = { headers: { 'Content-Type': `multipart/form-data; boundary=${form._boundary}` } };
/* Request to other endpoint */
let uploadResult = await axios.post(postUrl, form, myHeaders);
if (uploadResult.status == 200) return res.send(uploadResult).status(200);
/* PROBLEM HERE: this is the point the program never gets to and i need it to */
else {
return res.send(uploadResult).status(500);
}
}
catch (error) {
console.error("Unpredicted error occurred: ", error);
return res.send(error)
}
});
Вторая конечная точка:
app.post("/upload", async (req, res) => {
try {
await new Promise((resolve, reject) => {
/* upload the files to cloud */
uploadOnCloud.array("files")(req, res, (err) => {
if (err) {
console.error("Error happened successfully!", err)
return reject(err);
}
else
return resolve();
});
});
/* If no err detected, ends with 200 */
res.sendStatus(200);
}
catch (error) {
/* PROBLEM: can neither set status, nor anything else */
res.status(500).send(error.message);
}
});
Что здесь может быть не так?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Когда ваша вторая конечная точка отправляет статус 500, ваша первая конечная точка предполагает, что произошла ошибка, и переходит непосредственно к вашему catch. Вам необходимо указать там свой статус, чтобы решить вашу проблему:
catch (error) {
res.status(500).send(error.message);
}
Я обнаружил ошибку при воспроизведении исходного кода, который вы написали. Строка form.append("files", item.buffer, item.originalname) была неправильной. Должно быть так, как показано ниже. Кроме того, нет необходимости явно задавать Content-Type.
form.append("files",
new File([file_buffer], file_name, {
type: file_mimetype,
})
);
Кроме того, мне не удалось воспроизвести проблему зависания загрузки. Я думаю, это может быть связано с тем, что Мултер ждал данных в теле запроса, но их не было, поскольку вы прикрепили тело запроса без файлов!
Переменные
const cloudStorage = multer.memoryStorage();
const localStorage = multer.memoryStorage();
const cloudUploader = multer({
limits: {
fileSize: 1024 ** 3, // 1GB
},
storage: cloudStorage,
});
const localUploader = multer({
limits: {
fileSize: 100 * 1024 ** 2, // 100MB
},
storage: localStorage,
});
Маршрут загрузки файлов и его контроллер
app.post("/upload-files", localUploader.array("files"), async (req, res) => {
/** @type {Express.Multer.File[]} */ const files = req.files;
const form = new FormData();
form.append("someData", req.body["someData"]);
// ? You can perform your filter logic here on files
// Applying append function directly on files
files.forEach((file) => {
form.append(
"files",
new File([file.buffer], file.originalname, {
type: file.mimetype,
})
);
});
try {
const postUrl = `${process.env.ORIGIN}/upload`;
// Using built in node-fetch & no need to set Content-Type headers manually as form-data handles it
const uploadResult = await fetch(postUrl, {
method: "POST",
body: form,
});
if (uploadResult.ok) { // uploadResult.status is in range 200-299 ( success )
return res.status(200).json({
error: false,
message: "FILES UPLOADED SUCCESSFULLY!"
});
} else {
return res.status(500).json({
error: true,
message: "Something went wrong",
});
}
} catch (error) {
console.error(error);
return res.status(500).json(error);
}
});
Маршрут загрузки файла в облако и его контроллер
app.post("/upload", async (req, res) => {
try {
await new Promise((resolve, reject) => {
/* upload the files to cloud */
cloudUploader.array("files")(req, res, (err) => {
//? TO SEE EVERYTHING WORKS SAVING FILES TO LOCAL DISK
/** @type {Express.Multer.File[]} */ const files = req.files;
files.forEach((file) => {
fs.writeFileSync(`public/uploads/${file.originalname}`, file.buffer, {
encoding: "utf-8",
});
});
if (err) {
console.error("Error happened successfully!", err);
return reject(err);
} else return resolve();
});
});
return res.json({ error: false, message: "Files uploaded" });
} catch (e) {
console.error(e);
return res.json({ error: true, message: "Something went wrong" });
}
});
@Wren_Vaughan Я пытался воссоздать вашу реализацию API, но у меня есть предложение: зачем использовать Multer, если вы просто передаете файлы в другую конечную точку? Возможно, было бы проще обрабатывать данные файла непосредственно в запросе. В любом случае дайте мне знать, если это устранит ошибку, с которой вы столкнулись!
Большое спасибо за понимание, @Sanmeet! Мне пришлось внести некоторые изменения, чтобы ваш ответ соответствовал моему случаю, о котором я поделюсь очень скоро, но использование выборки с флагом «ошибка» заставило его работать. Я рассматривал возможность прямой обработки данных файла, как вы предложили. Однако я не так хорошо разбираюсь в теме обработки файлов, и у меня не было времени провести надлежащее исследование непосредственной обработки данных файла. Мне действительно не хотелось, чтобы один запрос на BE вызывал другой запрос на BE, но в тот момент это пришло в голову...
Еще одна вещь, @Sanmeet, заключается в том, что я вызвал ошибку, настроив fileFilter в параметрах моего Multer по второму запросу. Я сделал так, чтобы не принимать MIME-тип файла.
@Wren_Vaughan Ок, это объясняет часть фильтрации... также было приятно использовать флаг... и тогда вы переключились на простой запрос выборки, верно?! В любом случае я рад, что вы решили свою проблему. Кстати, вам следует изучить внутреннюю обработку файлов, это довольно интересно... как работает multer и все такое с обработкой файлов!
К сожалению, это не сработало. Я, конечно, не эксперт в Express, но думаю, что может быть так, что uploadOnCloud.array("files")(req, res, (err) {...} находится внутри другого запроса, но я не знаю, как чтобы они правильно работали вместе.