Node.js使用Multer上传图片报错:TypeError: 无法读取undefined的'image'属性
Node.js(Express+Multer+Mongoose)图片上传错误修正与原因分析
我编写的Node.js结合Express、Multer、Mongoose实现图片上传功能时,出现错误:TypeError: Cannot read properties of undefined(reading 'image'),以下是问题代码、错误原因及修正方案。
原代码
import bodyParser from "body-parser"; import express from "express"; import mongoose from "mongoose"; import ejs from "ejs"; import multer from "multer"; const app = express(); const port = 3000; app.set("view engine", "ejs"); app.use(bodyParser.urlencoded({ extended: true })); app.use(express.json()); app.use(express.static("public")); // Image Upload // Configure Multer const storage = multer.diskStorage({ destination: (req, file, cb) => { cb(null, "./uploads"); }, filename: (req, file, cb) => { cb(null, file.fieldname + "_" + Date.now + "_" + file.originalname); }, }); const upload = multer({ storage, }); // Connect to MongoDB database mongoose.connect("mongodb://127.0.0.1:27017/restaurantDB") .then(() => { console.log("Database Created Succesfuly"); }) .catch((err) => { comsole.log(err); }); const productSchema = new mongoose.Schema({ _id: { type: Number, required: true, }, name: { type: String, required: true, }, description: { type: String, required: true, }, price: { type: Number, required: true }, type: { type: String, required: true }, imagePath: { type: String, required: true } }); const Product = mongoose.model("Product", productSchema); app.get("/", (req, res) => { res.render("index.ejs"); }); app.get("/about", (req, res) => { res.render("about.ejs"); }); app.get("/contact", (req, res) => { res.render("contact.ejs"); }); app.get("/pizza", (req, res) => { res.render("pizza.ejs"); }); app.get("/burgur", (req, res) => { res.render("burgur.ejs"); }); app.get("/beverage", (req, res) => { res.render("beverage.ejs"); }); app.get("/addproduct", (req, res) => { res.render("addproduct.ejs"); }); app.get("/product", (req, res) => { res.render("product.ejs"); }); app.post("/addproduct", upload.single("image"), (req, res) => { const id = req.body["id"]; const name = req.body["name"]; const description = req.body["description"]; const price = req.body["price"]; const type = req.body["type"]; const file = req.file; if (!file) { // Handle the file upload error return res.status(400).send("File upload failed"); } const product = new Product({ _id: id, name: name, description: description, price: price, type: type, imagePath: `/uploads/${file.originalname}` }); product.save(); res.redirect("/product") }); app.listen(port, () => { console.log(`Server is running on port ${port}`); });
错误原因分析
Date.now未调用,应使用Date.now(),否则会将函数体作为字符串拼接,导致文件名异常- Mongoose连接错误处理中
comsole.log拼写错误,应为console.log - 前端表单未设置
enctype="multipart/form-data",导致Multer无法解析文件,req.file为undefined,进而引发读取image相关属性的错误 - 未确保
uploads目录存在,Multer不会自动创建该目录 imagePath使用file.originalname易导致文件名重复,应使用Multer生成的file.filename
修正后的代码
import bodyParser from "body-parser"; import express from "express"; import mongoose from "mongoose"; import ejs from "ejs"; import multer from "multer"; import fs from 'fs'; import path from 'path'; const app = express(); const port = 3000; const uploadsDir = path.join(__dirname, './uploads'); // 确保uploads目录存在 if (!fs.existsSync(uploadsDir)) { fs.mkdirSync(uploadsDir); } app.set("view engine", "ejs"); app.use(bodyParser.urlencoded({ extended: true })); app.use(express.json()); app.use(express.static("public")); // 让uploads目录可访问 app.use('/uploads', express.static(uploadsDir)); // Configure Multer const storage = multer.diskStorage({ destination: (req, file, cb) => { cb(null, uploadsDir); }, filename: (req, file, cb) => { // 调用Date.now()获取时间戳 cb(null, file.fieldname + "_" + Date.now() + "_" + file.originalname); }, }); const upload = multer({ storage, }); // Connect to MongoDB database mongoose.connect("mongodb://127.0.0.1:27017/restaurantDB") .then(() => { console.log("Database Connected Successfully"); }) .catch((err) => { // 修正拼写错误 console.log(err); }); const productSchema = new mongoose.Schema({ _id: { type: Number, required: true, }, name: { type: String, required: true, }, description: { type: String, required: true, }, price: { type: Number, required: true }, type: { type: String, required: true }, imagePath: { type: String, required: true } }); const Product = mongoose.model("Product", productSchema); // 路由部分保持不变 app.get("/", (req, res) => { res.render("index.ejs"); }); app.get("/about", (req, res) => { res.render("about.ejs"); }); app.get("/contact", (req, res) => { res.render("contact.ejs"); }); app.get("/pizza", (req, res) => { res.render("pizza.ejs"); }); app.get("/burgur", (req, res) => { res.render("burgur.ejs"); }); app.get("/beverage", (req, res) => { res.render("beverage.ejs"); }); app.get("/addproduct", (req, res) => { res.render("addproduct.ejs"); }); app.get("/product", (req, res) => { res.render("product.ejs"); }); app.post("/addproduct", upload.single("image"), async (req, res) => { const id = req.body["id"]; const name = req.body["name"]; const description = req.body["description"]; const price = req.body["price"]; const type = req.body["type"]; const file = req.file; if (!file) { return res.status(400).send("请选择要上传的图片"); } try { const product = new Product({ _id: id, name: name, description: description, price: price, type: type, // 使用multer生成的文件名 imagePath: `/uploads/${file.filename}` }); await product.save(); res.redirect("/product"); } catch (err) { res.status(500).send("保存产品失败:" + err.message); } }); app.listen(port, () => { console.log(`Server is running on port ${port}`); });
额外说明
前端表单必须设置enctype="multipart/form-data",示例代码如下:
<form action="/addproduct" method="post" enctype="multipart/form-data"> <input type="file" name="image" /> <!-- 其他表单字段 --> </form>
内容的提问来源于stack exchange,提问作者Tejasvi Kumar
相关产品推荐
相关产品推荐

