NodeJS Multer上传图片成功但请求Pending,后续请求被阻塞
多Fetch请求导致请求Pending且后续代码不执行的问题排查与解决
问题描述
在saveProduct函数中发起两个fetch请求:一个上传文件到/public/images目录,另一个提交产品数据到product表。第一个POST /api/upload能成功上传文件,但函数后续逻辑完全停滞——第二个请求一直处于pending状态,toast提示等代码也不执行。此前单请求模式下代码运行正常。
前端代码
const saveProduct = async () => { let formData = new FormData(); formData.append("image", product.image); setSubmitted(true); if (!product.image || !product.name|| !product.price) { return; } let _products = [...products]; let _product = { ...product }; Promise.all([ await fetch("http://localhost:8000/api/upload", { method: "POST", body: formData, }), await fetch("http://localhost:8000/api/new-product", { method: "POST", body: JSON.stringify(product), headers: { "Content-Type": "application/json" }, }), ]).then(() => { _products.push(_product); toast.current.show({ severity: "success", summary: "Successful", detail: "Product Created", life: 5000, }); setProducts(_products); setProductDialog(false); setProduct(emptyProduct); }); };
后端代码
import multer from "multer"; // Initialize router const routes = Router({ strict: true }); const storage = multer.diskStorage({ destination: function (req, file, cb) { return cb(null, "./public/images"); }, filename: function (req, file, cb) { return cb(null, `${Date.now()}_${file.originalname}`); }, }); const upload = multer({ storage }); routes.post("/upload", upload.single("image"), (req, res) => { console.log(req.body); console.log(req.file); }); routes.post( "/new-team-member", [ // Validation for user name body("name") .trim() .not() .isEmpty() .withMessage("product name must not be empty") .isLength({ min: 10 }) .withMessage("Full name must be at least 10 characters in length") .escape(), // Validation for password length body("price") .trim() .not .isEmpty() .withMessage("price must not be empty"), ], // tokenValidation(), // validate, // Middleware to handle validation errors (req, res) => { try { const { name, price, image } = req.body; DB.execute( "INSERT INTO `team` (`name`,`price`,`image`) VALUES (?,?,?)", [name, price, image] ); res.status(201).json({ name: name, price: price, image: image, }); } catch (err) { console.log(err); } } );
问题根源
- 后端/upload接口未返回响应:文件上传成功后,服务器没有通过
res.send()/res.json()返回任何响应,导致前端fetch一直处于等待状态(pending),Promise.all无法完成,后续代码自然不会执行。 - Promise.all使用错误:在
Promise.all数组中直接使用await,会导致两个请求串行执行,且如果第一个请求因无响应卡住,第二个请求根本不会触发。 - 路由不匹配:前端请求的是
/api/new-product,但后端定义的路由是/new-team-member,即使前面的问题解决,这个请求也会返回404。 - 数据库操作未处理异步:
DB.execute是异步函数,未加await会导致数据库插入操作还未完成就返回响应,同时错误捕获后也未向前端返回错误信息。 - 验证规则语法错误:
price字段的验证中,.not后缺少括号,应为.not().isEmpty(),导致验证逻辑失效。
修复方案
前端代码修改
去掉Promise.all中的await,直接传入fetch返回的Promise,同时添加错误处理:
const saveProduct = async () => { let formData = new FormData(); formData.append("image", product.image); setSubmitted(true); if (!product.image || !product.name|| !product.price) { return; } let _products = [...products]; let _product = { ...product }; try { await Promise.all([ fetch("http://localhost:8000/api/upload", { method: "POST", body: formData, }), fetch("http://localhost:8000/api/new-product", { method: "POST", body: JSON.stringify(product), headers: { "Content-Type": "application/json" }, }), ]); // 验证请求是否成功(可选:可添加response.ok判断) _products.push(_product); toast.current.show({ severity: "success", summary: "Successful", detail: "Product Created", life: 5000, }); setProducts(_products); setProductDialog(false); setProduct(emptyProduct); } catch (err) { console.error("请求失败:", err); toast.current.show({ severity: "error", summary: "Failed", detail: "Product Creation Failed", life: 5000, }); } };
后端代码修改
- 给
/upload接口添加响应:
routes.post("/upload", upload.single("image"), (req, res) => { console.log(req.body); console.log(req.file); // 返回上传成功的文件信息 res.status(200).json({ filename: req.file.filename, path: `/images/${req.file.filename}` }); });
- 修改产品接口路由为
/new-product,修复验证语法和异步操作:
routes.post( "/new-product", // 修正路由路径 [ body("name") .trim() .not() .isEmpty() .withMessage("product name must not be empty") .isLength({ min: 10 }) .withMessage("Full name must be at least 10 characters in length") .escape(), body("price") .trim() .not() // 补充括号 .isEmpty() .withMessage("price must not be empty"), ], async (req, res) => { // 改为async函数 try { const { name, price, image } = req.body; // await异步执行数据库操作 await DB.execute( "INSERT INTO `product` (`name`,`price`,`image`) VALUES (?,?,?)", // 修正表名为product [name, price, image] ); res.status(201).json({ name, price, image, }); } catch (err) { console.log(err); // 向前端返回错误响应 res.status(500).json({ error: "Failed to create product" }); } } );
内容的提问来源于stack exchange,提问作者Raneem Shoushari
相关产品推荐
相关产品推荐

