如何用Node.js API与React.js提交表单数据?报错求助
问题场景
我搭建了一个包含Express后端和React前端的项目,项目结构如下:
- Server.js
- ClientFolder(包含public目录和src目录,src下有Register.js组件)
- routes目录(包含users.js)
已经在package.json中配置了代理服务器,但在React的Register组件提交表单时,浏览器控制台出现两个错误:
Failed to load resource: the server responded with a status of 404 (Not Found)
index.js:1375 Error: SyntaxError: Unexpected token < in JSON at position 0
下面是相关代码,帮忙排查并解决表单提交失败的问题。
错误原因与修复步骤
1. 路由文件命名不匹配(导致404的核心原因)
你的Server.js中引入路由时使用的是./routes/users,但提供的路由文件是Routes/user.js(注意文件名是user.js而非users.js,还有目录名大小写差异)。Express会严格按照路径查找文件,找不到对应路由时会返回404错误,而服务器通常会返回HTML格式的错误页面,这就导致前端尝试解析JSON时遇到<(HTML标签的开头),触发Unexpected token <错误。
修复:
将路由文件重命名为users.js(保持和Server.js中的引入路径一致),或者修改Server.js中的引入路径为./routes/user(推荐前者,保持文件名复数形式的一致性)。
2. 路由处理函数中的变量名不统一
在routes/users.js中,你给路由处理函数的参数是request和response,但函数内部却使用了req和res,这会导致req is not defined的错误,进而服务器返回500错误,同样会导致前端解析JSON失败。
修复:
统一参数名,将函数参数改为req和res,修改后的路由代码:
const express = require('express'); const router = express.Router(); const jwt = require('jsonwebtoken'); // 引入Server.js中的数据库连接(需要先在Server.js导出connection) const connection = require('../Server').connection; router.use(express.urlencoded({ extended: true })); router.use(express.json()); // 统一参数名为req和res router.post('/', function(req, res) { var user = { username: req.body.username, email: req.body.email, password: req.body.password, userType: req.body.userType, team: req.body.team }; connection.query('INSERT INTO players SET ?', user, function(error, results, fields) { if (error) { console.log('error occurred', error); res.send({ code: 400, failed: 'error occurred' }); } else { console.log('The solution is: ', results); res.send({ code: 200, success: 'user registered successfully' }); } }); }); module.exports = router;
同时在Server.js中导出数据库连接:
// 在Server.js的connection定义后添加 module.exports.connection = connection;
3. 数据库连接未在路由中可用
路由文件routes/users.js中直接使用了connection变量,但这个变量是在Server.js中定义的,路由文件无法直接访问,会导致ReferenceError: connection is not defined错误。
修复:
如上面的代码所示,在Server.js中导出connection并在路由文件中引入;更规范的做法是将数据库连接逻辑抽离到单独的文件(比如db.js),然后在Server.js和路由文件中统一引入。
4. React组件中select标签的onChange事件丢失
在Register组件的select标签中,onChange={this.handleUserTypeChange}被注释掉了,导致用户选择的userType无法更新到组件状态,提交时该字段为空,可能引发后端数据库插入失败。
修复:
恢复select标签的onChange事件:
<select id='userType' value={this.state.userType} onChange={this.handleUserTypeChange} className='form-control' required > <option value='Staff'>Staff</option> <option value='Player'>Player</option> </select>
5. React组件state中重复定义username
在Register组件的constructor中,重复定义了username: '',属于代码冗余,虽然不影响功能,但需要修正:
constructor() { super(); this.state = { username: '', email: '', password: '', userType: '', team: '' }; this.handleSubmit = this.handleSubmit.bind(this); }
6. React组件中错误状态的大小写不一致
在Register组件的team输入框中,错误状态使用了this.state.TeamError(大写T),但在validateTeam方法中设置的是teamError(小写t),导致错误提示无法正确显示:
<input id='team' className={`form-control ${ this.state.teamError ? 'is-invalid' : '' }`} type='text' onChange={this.handleTeamChange} onBlur={this.validateTeam} required /> <div className='invalid-feedback'>{this.state.teamError}</div>
额外优化建议
- 前端fetch请求中添加状态检查,更清晰地捕获服务器错误:
fetch('/users', { method: 'POST', body: JSON.stringify(formData), headers: { 'Content-Type': 'application/json' } }) .then(res => { if (!res.ok) throw new Error(`HTTP error! status: ${res.status}`); return res.json(); }) .catch(error => console.error('Error:', error)) .then(response => console.log('Success:', response));
- 后端可移除单独的
body-parser依赖,因为Express 4.16+已内置JSON和URL编码解析中间件,直接使用app.use(express.json())和app.use(express.urlencoded())即可。
内容的提问来源于stack exchange,提问作者John

