繁体   English   中英

当文件作为“multipart/form-data”发送时,Express Route 返回状态代码 500 和通用“错误”

[英]Express Route returns status code 500 with generic 'Error' when file is sent as 'multipart/form-data'

细节:

我有一个快速路由,它设置为接受文件作为multipart/formdata并将它们上传到 S3 存储桶。 我正在使用multer过滤图像类型,并通过创建upload目录将它们临时存储在服务器上。 上传成功后不久,文件将被删除。 文件数组根据 multer 配置命名为images ,最多接受 3 个图像。

该代码在我的本地机器上完美运行。 我通过 POSTMAN 进行测试,可以上传 1-3 个文件并得到正确的响应。 如果没有附加文件,也会触发正确的响应,状态码均为 200。

问题

完全相同的代码库使用 Docker 部署在 Amazon ECS 上,但不知何故一直失败,状态代码为 500 和代码库中未找到的通用“错误”消息。 使用日志我确定 multer 不是原因,因为它通过了过滤器。 它似乎在 multer 中间件和路由本身之间的某个地方出现故障,但有一个例外。

例外:使用 POSTMAN,如果在没有文件 IE 空images数组的情况下发出multipart/formdata POST 请求,则会正确触发路由并返回消息“您没有附加任何图像”作为响应。

如果可以就这个问题提供一些指导,我一直无法弄清楚这个问题并感激不尽!

代码片段:

文件控制器:

files.post(
  "/multiple",
  upload.array("images", 3),
  async (req: ExpressRequest, res: ExpressResponse) => {
    try {
      const files: { [fieldname: string]: Express.Multer.File[] } | Express.Multer.File[] =
        req.files;
      console.log("FILES", files);
      // execute only if there are files
      if (files.length > 0) {
        const dataPromises = (files as Array<Express.Multer.File>).map(
          async (file: Express.Multer.File) => {
            // check if file.mimetype here is 'image/heic', and convert into jpeg accordingly
            const fileNameWithoutExt = file.filename.split(".")[0];
            try {
              if (file.mimetype == "image/heic") {
                await convertFile(file, fileNameWithoutExt, 0.2);
                const response = await uploadFilePath(
                  S3_IMAGE_BUCKET,
                  `./uploads/${fileNameWithoutExt}.jpeg`,
                  `${fileNameWithoutExt}.jpeg`
                );
                console.log("HEIC File Upload Response", response);
                fs.unlinkSync(`./uploads/${fileNameWithoutExt}.jpeg`);
                fs.unlinkSync(file.path);
                return {
                  fileName: `${fileNameWithoutExt}.jpeg`,
                  metaData: response.$metadata,
                };
              } else {
                const response = await uploadFile(S3_IMAGE_BUCKET, file);
                console.log("JPEG File Upload Response", response);
                fs.unlinkSync(file.path);
                return {
                  fileName: file.filename,
                  metaData: response.$metadata,
                };
              }
            } catch (err) {
              console.error("Error for file conversion/upload", err, err.stack);
              res.status(500).send({
                message: "Upload failed due to conversion or something.",
                error: err,
                stack: err.stack,
              });
            }
          }
        );
        const fileData = await Promise.all(dataPromises);
        const fileNames = fileData.map((data: any) => data.fileName);
        const statusCodes = fileData.map((data: any) => data.metaData.httpStatusCode);

        if (statusCodes.find((statusCode) => statusCode === 200)) {
          res.status(200).send({
            filePath: `/image/`,
            fileNames,
          });
        } else {
          res.status(403).send({
            message: "Upload failed. Please check credentials or file has been selected.",
          });
        }
      } else {
        res.status(200).send({
          message: "You did not attach any images",
        });
      }
    } catch (err) {
      res.status(500).send({
        message: "Upload failed. Please check credentials or file has been selected.",
      });
    }
  }
);

多路复用器配置:

const storage = multer.diskStorage({
  // potential error, path to store files, callback
  destination: (req, file, cb) => {
    // cb acceptes two arguments: 1. err 2. destination folder wrt to server.js
    cb(null, "uploads/");
  },
  filename: (req, file, cb) => {
    console.log("MULTER STORAGE STARTED")
    const date = new Date().toISOString().substring(0, 10);
    // const name = `${req.body.first_name}_${req.body.last_name}`;
    // cb defines the name of the file when stored
    const alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-";
    const nanoid = customAlphabet(alphabet, 20);
    cb(null, `${date}_${nanoid()}_${file.originalname}`);
    console.log("FILE NAME CREATED, MULTER STORAGE STOPPED")
  },
});

/* Accept jpeg or png files only */
// NOTE: file type rejection works, but there is no error message displayed if file is rejected. logic in route continues to be executed
const fileFilter = (
  req: Request,
  file: Express.Multer.File,
  cb: (error: Error | null, accepted: boolean) => void
) => {
  console.log("======== FILE FILTER ========", file);
  if (
    file.mimetype === "image/jpeg" ||
    file.mimetype === "image/png" ||
    file.mimetype === "image/heic"
  ) {
    cb(null, true);
    console.log("FILTER PASSED")
  } else {
    console.log("FILTER FAILED");
    cb(null, false);
  }
};

/* Only accepts filesize up to 5MB */
// the first parameter is super important that determines where the data is stored on the server
const upload = multer({
  dest: "uploads/", // default simple config to upload file as binary data
  storage, // enable if storage of actual file is required.
  // limits: { fileSize: 1024 * 1024 * 5 },
  fileFilter,
});

截图:

表单数据中没有图像的响应表单数据中没有图像的响应

用表单数据中的图像响应用表单数据中的图像响应

你能确保上传目录存在于你的 Docker 容器中吗? 如果它不存在,Multer 将不会创建它。 它可能在您的storage function 和文件实际写入磁盘之间静默失败。

const storage = multer.diskStorage({
  // potential error, path to store files, callback
  destination: (req, file, cb) => {
    // cb acceptes two arguments: 1. err 2. destination folder wrt to server.js
    cb(null, "uploads/");
  },

应该是这样的:

import { access, constants } from "fs";
import { join } from "path";
...
const storage = multer.diskStorage({
  // potential error, path to store files, callback
  destination: (req, file, cb) => {
    // cb acceptes two arguments: 1. err 2. destination folder wrt to server.js
    const currentDirectory: string = process.cwd();
    const uploadDirectory: string = join(currentDirectory, 'uploads/');
    // can we write to this path?
    access(uploadDirectory, constants.W_OK, (err) => {
      if (err) {
        console.error(err);
        cb(err, null);
      }
      cb(null, uploadDirectory);
    })
  },

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM