Конечная точка запроса на Express не перестанет загружаться, даже если я установлю статус ответа (проблемы с Multer и Express)

Я работаю над созданием фильтра, основанного на оценке подписи файла, полученной через файловый буфер, предоставленный Multer. Я знаю, что Multer предоставляет тип MIME, но мне также нужно проверить, действительно ли файл относится к этому типу MIME, используя некоторые другие способы проверки.

По этой причине мои действия таковы:

  1. Временно сохраните файлы запроса в памяти MulterStorage(), чтобы получить буфер, затем
  2. Фильтровать действительные файлы
  3. Добавьте эти действительные файлы и другую информацию, которая мне нужна для вновь созданного FormData.
  4. Сделайте запрос POST к другой конечной точке ("/upload") с новым FormData.
  5. Храните файлы в облаке с помощью Multer

ПРОБЛЕМА: Как только я вызываю какую-то ошибку на второй конечной точке, процесс зацикливается. Ошибка обнаружена, однако я не могу вернуть какой-либо 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);
    }
});

Что здесь может быть не так?

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
53
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Когда ваша вторая конечная точка отправляет статус 500, ваша первая конечная точка предполагает, что произошла ошибка, и переходит непосредственно к вашему catch. Вам необходимо указать там свой статус, чтобы решить вашу проблему:

catch (error) {
    res.status(500).send(error.message);
}

К сожалению, это не сработало. Я, конечно, не эксперт в Express, но думаю, что может быть так, что uploadOnCloud.array("files")(req, res, (err) {...} находится внутри другого запроса, но я не знаю, как чтобы они правильно работали вместе.

Wren_Vaughan 30.05.2024 20:44
Ответ принят как подходящий

Я обнаружил ошибку при воспроизведении исходного кода, который вы написали. Строка 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 30.05.2024 21:45

Большое спасибо за понимание, @Sanmeet! Мне пришлось внести некоторые изменения, чтобы ваш ответ соответствовал моему случаю, о котором я поделюсь очень скоро, но использование выборки с флагом «ошибка» заставило его работать. Я рассматривал возможность прямой обработки данных файла, как вы предложили. Однако я не так хорошо разбираюсь в теме обработки файлов, и у меня не было времени провести надлежащее исследование непосредственной обработки данных файла. Мне действительно не хотелось, чтобы один запрос на BE вызывал другой запрос на BE, но в тот момент это пришло в голову...

Wren_Vaughan 31.05.2024 14:48

Еще одна вещь, @Sanmeet, заключается в том, что я вызвал ошибку, настроив fileFilter в параметрах моего Multer по второму запросу. Я сделал так, чтобы не принимать MIME-тип файла.

Wren_Vaughan 31.05.2024 14:52

@Wren_Vaughan Ок, это объясняет часть фильтрации... также было приятно использовать флаг... и тогда вы переключились на простой запрос выборки, верно?! В любом случае я рад, что вы решили свою проблему. Кстати, вам следует изучить внутреннюю обработку файлов, это довольно интересно... как работает multer и все такое с обработкой файлов!

Sanmeet 31.05.2024 16:15

Другие вопросы по теме