You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js+TypeScript+Multer S3上传报错:Cannot read properties of undefined (reading 'map')

问题:整合S3上传逻辑到住宿控制器后出现Cannot read properties of undefined (reading 'map')错误

我原本实现了一个可正常将文件上传至S3存储桶的独立路由,但将该上传逻辑整合到Accommodation控制器并添加额外业务逻辑后,出现错误:Cannot read properties of undefined (reading 'map')。我在Postman中对两个路由使用了完全相同的请求,求排查问题所在。

相关代码

原上传控制器逻辑

import { Request, Response } from "express";
import catchBlock from "../utils/catchBlock";
import { s3Uploadv2 } from "../utils/s3Service";

const UploadController = {
  Upload: async (req: Request, res: Response) => {
    const files = req.files as Express.Multer.File[];
    try {
      const results = await s3Uploadv2(files);
      res.send({ success: "successful", results });
    } catch (e: unknown) {
      catchBlock(e, res);
    }
  },
};

export default UploadController;

住宿模块上传逻辑

UploadImages: async (req: Request, res: Response) => {
    const accommodationId = req.params.id;
    const accommodation = await accommodationSchema.findOne({
      _id: accommodationId,
    });
    const files = req.files as Express.Multer.File[];

    try {
      const results = await s3Uploadv2(files);
      console.log(results);
      if (accommodation) {
        results.forEach((file) => accommodation.photos.push(file.Location));
        await accommodation.save();
        res.send({ success: "successful", accommodation });
      } else {
        res.status(400).send("No such accommodation");
      }
      res.send({ success: "successful", results });
    } catch (e: unknown) {
      catchBlock(e, res);
    }
  },

S3服务代码

import { S3 } from "aws-sdk";
import { v4 as uuid } from "uuid";

export interface Param {
  Bucket: string;
  Key: string;
  Body: Buffer;
}

export const s3Uploadv2 = async (files: Express.Multer.File[]) => {
  const s3 = new S3();
  const params: Param[] = files.map((file) => {
    return {
      Bucket: process.env.AWS_BUCKET_NAME,
      Key: `uploads/${uuid()}-${file.originalname}`,
      Body: file.buffer,
    };
  });

  const results = await Promise.all(
    params.map((param) => s3.upload(param).promise())
  );

  return results;
};

Multer服务代码

import multer, { FileFilterCallback, MulterError } from "multer";
import { Request } from "express";

const storage = multer.memoryStorage();

const fileFilter = (
  req: Request,
  file: Express.Multer.File,
  cb: FileFilterCallback
) => {
  if (file.mimetype.split("/")[0] === "image") {
    cb(null, true);
  } else {
    cb(new MulterError("LIMIT_UNEXPECTED_FILE"));
  }
};

export const upload = multer({
  storage,
  fileFilter,
  limits: { fileSize: 1000000, files: 5 },
});

住宿模块路由

import express from "express";
import AccommodationController from "../controllers/accommodation";
const accommodationRouter = express.Router();

accommodationRouter.get("/", AccommodationController.All);
accommodationRouter.post(
  "/create",
  AccommodationController.CreateAccommodation
);
accommodationRouter.get(
  "/users-accommodation",
  AccommodationController.UsersAccommodation
);
accommodationRouter.post("/delete/:id", AccommodationController.Delete);
accommodationRouter.post("/upload/:id", AccommodationController.UploadImages);

export default accommodationRouter;

上传模块路由

import express from "express";
import UploadController from "../controllers/upload";
import { upload } from "../utils/multer";
const uploadRouter = express.Router();

uploadRouter.post("/", upload.array("file", 5), UploadController.Upload);

export default uploadRouter;

问题排查与修复

核心错误原因

你在住宿模块的上传路由中没有挂载multer的upload.array("file",5)中间件。原上传路由正是通过这个中间件解析上传的文件,并把解析后的文件列表挂载到req.files上;而住宿模块的路由直接调用控制器,导致req.files为undefined,当s3Uploadv2函数执行files.map时,就会抛出Cannot read properties of undefined (reading 'map')的错误。

修复步骤

修改住宿模块的路由,在UploadImages控制器前添加multer中间件:

// 先导入multer的upload实例
import { upload } from "../utils/multer";

// 修改上传路由
accommodationRouter.post("/upload/:id", upload.array("file",5), AccommodationController.UploadImages);

额外注意事项

  1. 检查你的accommodationSchema中photos字段是否已初始化为数组类型(比如photos: { type: [String], default: [] }),避免accommodation.photos为undefined导致push报错。
  2. 住宿控制器的UploadImages方法中存在双重响应的问题:在if(accommodation)分支里执行了res.send,之后又执行了一次res.send,这会导致Express抛出Cannot set headers after they are sent to the client的错误,需要移除其中一个响应语句。

内容的提问来源于stack exchange,提问作者Chris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 08:20:28