电商网站产品图片上传报错:Cannot read properties of undefined (reading 'post')
电商网站产品图片上传报错:Cannot read properties of undefined (reading 'post')
搭建电商网站时,尝试上传本地图片修改产品图片失败,报错信息:Cannot read properties of undefined (reading 'post')
错误截图:
相关代码文件
uploadRouter.js
import multer from "multer"; import express from "express"; import { isAuth } from "../util"; const uploadRouter = express.Router(); const storage = multer.diskStorage({ destination(req, file, cb) { cb(null, "uploads/"); }, filename(req, file, cb) { cb(null, `${Date.now()}.jpg`); }, }); const upload = multer({ storage }); uploadRouter.post("/", isAuth, upload.single("image"), (req, res) => { res.send(`/${req.file.path}`); }); export default uploadRouter;
server.js
import express from "express"; import dotenv from "dotenv"; import mongoose from "mongoose"; import path from "path"; import userRoute from "./routes/userRoute"; import productRoute from "./routes/productRoute"; import orderRouter from "./routes/orderRouter"; import uploadRouter from "./routes/uploadRouter"; dotenv.config(); const app = express(); app.use(express.json()); app.use(express.urlencoded({ extended: true })); mongoose.connect(process.env.MONGODB_URL || "mongodb://localhost/amason", { useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true, }); app.use("/api/uploads", uploadRouter); app.use("/api/users", userRoute); app.use("/api/products", productRoute); app.use("/api/orders", orderRouter); const __dirname = path.resolve(); app.use("/uploads", express.static(path.join(__dirname, "/uploads"))); app.get("/", (req, res) => { res.send("Server is ready"); }); app.use((err, req, res, next) => { res.status(500).send({ message: err.message }); }); const port = process.env.PORT || 5000; app.listen(port, () => { console.log(`Serve at http://localhost:${port}`); });
productEditPage.jsx
import React, { useEffect, useState } from "react"; import { useDispatch, useSelector } from "react-redux"; import { detailsProduct, updateProduct } from "../actions/productActions"; import LoadingBox from "../components/loadingBox"; import MessageBox from "../components/messageBox"; import { PRODUCT_UPDATE_RESET } from "../reducers/actionTypes"; import { axios } from "axios"; import NavBar from "../components/navbar"; import Footer from "../components/footer"; function ProductEditPage(props) { const productId = props.match.params.id; const [name, setName] = useState(""); const [price, setPrice] = useState(""); const [category, setCategory] = useState(""); const [image, setImage] = useState(""); const [brand, setBrand] = useState(""); const [countInStock, setCountInStock] = useState(""); const [description, setDescription] = useState(""); const productDetails = useSelector((state) => state.productDetails); const { loading, error, product } = productDetails; const productUpdate = useSelector((state) => state.productUpdate); const { loading: loadingUpdate, error: errorUpdate, success: successUpdate, } = productUpdate; const dispatch = useDispatch(); useEffect(() => { if (successUpdate) { props.history.push("/productlist"); } if (!product || product._id !== productId || successUpdate) { dispatch({ type: PRODUCT_UPDATE_RESET }); dispatch(detailsProduct(productId)); } else { setName(product.name); setPrice(product.price); setImage(product.image); setCategory(product.category); setCountInStock(product.countInStock); setBrand(product.brand); setDescription(product.description); } }, [product, dispatch, productId, successUpdate, props.history]); const submitHandler = (e) => { e.preventDefault(); dispatch( updateProduct({ _id: productId, name, price, image, brand, category, countInStock, description, }) ); }; const [loadingUpload, setLoadingUpload] = useState(false); const [errorUpload, setErrorUpload] = useState(""); const userSignin = useSelector((state) => state.userSignin); const { userInfo } = userSignin; const uploadFileHandler = async (e) => { const file = e.target.files[0]; const bodyFormData = new FormData(); bodyFormData.append("image", file); setLoadingUpload(true); try { const { data } = await axios.post("/api/uploads", bodyFormData, { headers: { "Content-Type": "multipart/form-data", Authorization: `Bearer ${userInfo.token}`, }, }); setImage(data); setLoadingUpload(false); } catch (error) { setErrorUpload(error.message); setLoadingUpload(false); console.log(error); } }; return ( <div className="container "> <div className="row content "> <div className="row justify-content-between content_header mt-4"> <div className="col-4"> <p>Edit Product {productId}</p> </div> </div> {loadingUpdate && <LoadingBox></LoadingBox>} {errorUpdate && ( <MessageBox variant="danger">{errorUpdate}</MessageBox> )} {loading ? ( <LoadingBox></LoadingBox> ) : error ? ( <MessageBox variant="danger">{error}</MessageBox> ) : ( <> <div className="row "> <form className=" edit mt-5 mb-5 col col-lg-8 " onSubmit={submitHandler} > <div className="row g-3"> <div className="col mb-3"> <label htmlFor="name" className="form-label"> Name </label> <input type="text" className="form-control " id="name" value={name} placeholder="Enter name" onChange={(e) => setName(e.target.value)} /> </div> <div className="col mb-4"> <label htmlFor="price" className="form-label"> Price </label> <input type="text" className="form-control" id="price" value={price} placeholder="Enter price" onChange={(e) => setPrice(e.target.value)} /> </div> </div> <div className="row g-3"> <div className="col mb-4"> <label htmlFor="brand" className="form-label"> Brand </label> <input type="text" className="form-control" id="brand" value={brand} placeholder="Enter brand" onChange={(e) => setBrand(e.target.value)} /> </div> </div> <div className="col mb-4"> <label htmlFor="image" className="form-label"> Image </label> <input type="text" className="form-control" id="image" value={image} placeholder="Enter image" onChange={(e) => setImage(e.target.value)} /> </div> <div className="mb-4"> <label htmlFor="imageFile" className="form-label"> Image File </label> <input className="form-control" type="file" id="imageFile" label="Choose Image" onChange={uploadFileHandler} multiple /> {loadingUpload && <LoadingBox></LoadingBox>} {errorUpload && ( <MessageBox variant="danger">{errorUpload}</MessageBox> )} </div> <div className="row g-3"> <div className="col mb-4"> <label htmlFor="countInStock" className="form-label"> CountInStock </label> <input type="text" className="form-control" id="countInStock" value={countInStock} placeholder="Enter countInStock" onChange={(e) => setCountInStock(e.target.value)} /> </div> <div className="col mb-4"> <label htmlFor="category" className="form-label"> Category </label> <input type="text" className="form-control" id="category" value={category} placeholder="Enter category" onChange={(e) => setCategory(e.target.value)} /> </div> </div> <div className="mb-4"> <label htmlFor="description" className="form-label"> Description </label> <textarea className="form-control" id="description" value={description} placeholder="Enter description" onChange={(e) => setDescription(e.target.value)} /> </div> <div className="row g-3"> <div className="col mb-4 "> <button type="submit" className="btn btn-secondary "> Update </button> </div> </div> </form> </div> </> )} </div> </div> ); }
问题解决方法
报错核心原因是axios导入方式错误:
在productEditPage.jsx中,你使用了命名导入import { axios } from "axios";,但axios是默认导出,正确的导入方式应该是:
import axios from "axios";
修改后,axios对象会被正确加载,调用axios.post时就不会出现undefined报错。
额外检查点:
- 确认项目根目录下的
uploads文件夹已创建,multer需要该目录存储上传文件 - 验证后端
/api/uploads路由已正确挂载,且isAuth中间件能正常验证用户权限 - 确保上传的文件符合multer配置的类型(当前只处理jpg,可根据需求扩展)
内容的提问来源于stack exchange,提问作者Susan
相关产品推荐
相关产品推荐

