Node.js前后端连接异常:前端表单无法正确提交数据
前后端表单提交数据校验失败问题解决方案
问题描述
前端HTML表单提交数据到后端时,Joi校验中间件提示"name" is required,"address" is required,"contact" is required,即后端未接收到前端传递的表单数据,但各部分代码可独立运行,需解决数据传递异常问题。
相关代码展示
控制器代码
const memberModel =require('../models/index').member const Op = require('sequelize').Op exports.getAllMember = async (request, response) => { let members = await memberModel.findAll() return response.json({ success:true, data:members, message: 'member ke load' }) } exports.addMember = (request,response) => { let newMember = { name: request.body.name, address: request.body.address, gender: request.body.gender, contact: request.body.contact } memberModel.create(newMember) .then(result => { return response.json({ success: true, data:result, message: 'new membruh' }) }) .catch(error => { return response.json({ success: false, message: error.message }) }) }
路由代码
const express = require('express') const app = express() app.use(express.json()) const memberController = require('../controllers/member.controller') let { validateMember } = require(`../middlewares/member-validation`) app.get("/", memberController.getAllMember) app.post("/", [validateMember], memberController.addMember) module.exports = app
中间件代码
const Joi = require(`joi`) const validateMember = (request, response, next) => { const rules = Joi .object() .keys({ name: Joi.string().required(), address: Joi.string().required(), contact: Joi.number().required(), gender: Joi.string().valid(`Male`, `Female`) }) .options({ abortEarly: false}) let { error } = rules.validate(request.body) if (error != null){ let errMessage = error.details.map( it => it.message).join(",") return response.status(422).json({ success: false, message: errMessage }) } next() } module.exports = {validateMember}
主文件代码
const express = require('express'); const app = express(); const PORT = 8000; // Use uppercase for constant variable const cors = require('cors'); const bodyParser = require('body-parser'); // Import body-parser app.use(bodyParser.urlencoded({ extended: true })); // Use body-parser to parse form data app.use(bodyParser.json()); app.use(cors()); // Use app.use() for middleware const memberRoute = require('./routes/member.route') app.use('/member', memberRoute) app.listen(PORT,() => { console.log('lezgo 8000') } )
前端HTML表单代码
<!DOCTYPE html> <html> <head> <title>Add Member</title> </head> <body> <h1>Add Member</h1> <form id="memberForm" name="memberForm"> <label for="name">Name:</label> <input type="text" id="name" name="name" required><br> <label for="gender">Gender:</label> <select id="gender" name="gender" required> <option value="male">Male</option> <option value="female">Female</option> </select><br> <label for="address">Address:</label> <input type="text" id="address" name="address" required><br> <label for="contact">Contact:</label> <input type="text" id="contact" name="contact" required><br> <button type="submit">Submit</button> </form> <div id="message"></div> <script> const memberForm = document.getElementById('memberForm'); const message = document.getElementById('message'); memberForm.addEventListener('submit', async (e) => { e.preventDefault(); const formData = new FormData(memberForm); try { const response = await fetch('http://localhost:8000/member', { method: 'POST', body: formData, }); const data = await response.json(); if (data.success) { message.innerHTML = data.message; memberForm.reset(); } else { message.innerHTML = data.message; } } catch (error) { message.innerHTML = error.message; } }); </script> </body> </html>
问题原因分析
- 数据格式不匹配:前端用
FormData发送multipart/form-data格式数据,但后端仅配置了json和urlencoded格式的解析中间件,无法解析该类型数据,导致request.body为空,触发必填字段缺失的校验错误。 - 性别值大小写不匹配:前端下拉框的性别值为小写
male/female,但后端Joi校验规则要求的是大写开头的Male/Female,即使数据传递成功也会触发校验失败。
解决方案
方案1:修改前端请求为JSON格式(推荐)
利用后端已配置的express.json()中间件,将表单数据转为JSON格式发送,同时统一性别值格式:
memberForm.addEventListener('submit', async (e) => { e.preventDefault(); // 将表单数据转为JSON对象 const formData = new FormData(memberForm); const payload = Object.fromEntries(formData); // 统一性别值为开头大写格式 payload.gender = payload.gender.charAt(0).toUpperCase() + payload.gender.slice(1); try { const response = await fetch('http://localhost:8000/member', { method: 'POST', headers: { 'Content-Type': 'application/json' // 指定请求格式为JSON }, body: JSON.stringify(payload), // 转为JSON字符串发送 }); const data = await response.json(); if (data.success) { message.innerHTML = data.message; memberForm.reset(); } else { message.innerHTML = data.message; } } catch (error) { message.innerHTML = error.message; } });
方案2:后端添加multipart/form-data解析中间件
若坚持使用FormData发送数据,需安装并配置multer中间件解析该格式,同时修正性别值匹配问题:
- 安装
multer:
npm install multer
- 修改主文件代码,添加
multer配置:
const express = require('express'); const app = express(); const PORT = 8000; const cors = require('cors'); const bodyParser = require('body-parser'); const multer = require('multer'); // 引入multer const upload = multer(); // 初始化multer,仅解析字段不存储文件 app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); app.use(upload.none()); // 解析multipart/form-data格式的普通字段 app.use(cors()); const memberRoute = require('./routes/member.route') app.use('/member', memberRoute) app.listen(PORT,() => { console.log('lezgo 8000') } )
- 修正性别值匹配:
- 要么修改前端下拉框的value值:
<select id="gender" name="gender" required> <option value="Male">Male</option> <option value="Female">Female</option> </select> - 要么修改后端Joi校验规则:
gender: Joi.string().valid(`Male`, `Female`, `male`, `female`)
- 要么修改前端下拉框的value值:
内容的提问来源于stack exchange,提问作者Mu Za
相关产品推荐
相关产品推荐

