为何未用body-parser时Express.js仅能读取部分req.body变量?
问题描述
未手动引入body-parser,但Express后端通过req.body读取变量时,title、text、test能正常获取对应值,picturePath和fruit却显示undefined。前端定义了5个变量:title(字符串)、text(字符串)、picturePath(对象)、fruit(字符串)和test(字符串),前端控制台打印所有变量均正常,但后端接收异常。
后端路由代码:
router.put("/:id/two", VerifyToken, upload.single("file"), async (req, res) => { try { const blogPostId = req.params.id; const { title, text, picturePath, fruit, test } = req.body; if (req.file === undefined) { const data = await BlogPostsModel.findByIdAndUpdate(blogPostId, { title, text }); if (!data) { throw new Error('An error occurred while updating blog post') } res.status(200).json(data); } else { const data = await BlogPostsModel.findByIdAndUpdate(blogPostId, { title, text, picturePath: req.file.filename }); if (!data) { throw new Error('An error occurred while updating blog post') } res.status(200).json(data); } } catch (error) { res.status(500).json({error: 'An error occurred while updating blog post...'}) } })
前端PUT请求函数:
const UpdateBlogPost = async (e, title, text, picturePath, test) =>{ e.preventDefault(); console.log(typeof(picturePath), typeof(title), typeof(text), typeof(fruit), typeof(test)) try { const formdata = new FormData() formdata.append('file', picturePath) formdata.append('title', title) formdata.append('text', text) formdata.append('base', fruit) formdata.append('test', test) const response = await fetch(`${baseUrl}/blogPosts/${blogpostId}`, { method: "PUT", headers: { authorization: token}, body: formdata }) if (response.ok) { Navigate(`/blogPost/${blogpostId}`); } } catch(error){ console.log(error); } }
核心原因分析
键名不匹配导致
fruit为undefined
前端FormData中用formdata.append('base', fruit)添加fruit变量,但后端解构时用的是fruit,前后端键名完全不一致,后端找不到对应字段,因此fruit显示undefined。picturePath未被添加到FormData中
前端的picturePath是文件对象,但你仅将它以file为键添加到FormData(formdata.append('file', picturePath)),并未添加picturePath这个键的字段。后端req.body.picturePath没有对应数据源,所以返回undefined。为什么其他变量能正常读取?
Express从v4.16.0版本开始,已经内置了express.urlencoded()和express.json()(这两个是body-parser的核心解析逻辑),所以即使不手动引入body-parser,符合application/x-www-form-urlencoded或application/json格式的请求也会被自动解析到req.body。而你使用的是multipart/form-data格式(FormData),Express默认不处理这类格式,但你引入的multer中间件(upload.single("file"))会负责解析FormData中的文件和文本字段,并将文本字段存入req.body——这就是title、text、test能被正常读取的原因,因为它们的前后端键名完全对应。
修复方案
- 修改前端代码,将
formdata.append('base', fruit)改为formdata.append('fruit', fruit),保证前后端键名一致。 - 如果你确实需要在
req.body中拿到picturePath,可以在前端FormData中添加formdata.append('picturePath', picturePath),不过从后端现有逻辑来看,你已经通过req.file.filename获取了图片路径并赋值给了picturePath,所以解构req.body.picturePath本身属于冗余操作,可直接删除该变量的解构。
内容的提问来源于stack exchange,提问作者Alesf28

