Node.js搭建授权登录时JSON数据第1行第1列出现意外字符报错
问题修复说明
你遇到的400请求错误和JSON解析报错是前后端多处逻辑错误共同导致的,具体问题和修复方法如下:
前端问题(login.ejs)
- fetch请求的
body参数错误:你使用了JSON.parse(JSON.stringify({username, password})),这套操作最终返回的是JS原生对象,不是JSON字符串。而你设置了请求头Content-Type: application/json,服务端会尝试将请求体解析为JSON,接收到JS对象就会解析失败返回400,且返回的错误内容不是JSON格式,前端调用res.json()就会抛出解析异常。 - 修复方法:去掉多余的
JSON.parse,直接传入JSON.stringify返回的JSON字符串即可。
后端问题(login.js)
- 路由第一行就执行了
res.json({status: 'ok'}),直接返回了响应,后续所有注册逻辑完全不会执行,且后续尝试再次返回res.json会触发重复返回响应的报错。 - 没有从请求体中提取
username和password变量,直接使用未定义的变量会触发运行时报错。 - 密码校验逻辑写错:
if(!password || typeof username !== 'string')这里错误校验了username的类型,没有校验密码的类型。 - 重复声明
password变量:后续使用const password = await bcrypt.hash(...)会和前面的password变量冲突,触发变量重复声明报错。 - 密码长度校验逻辑不匹配:判断条件是
password.length < 5,但错误提示要求至少6位,逻辑不一致。 - catch块执行顺序错误:先执行
throw error再打印日志,打印代码永远不会执行;且抛出错误没有做兜底返回,前端接收到的是非JSON格式的报错内容。 - 额外需要确认:你的express主文件需要注册
express.json()中间件,否则无法解析JSON格式的请求体,也会导致400报错。
修正后代码示例
前端fetch部分
const result = await fetch('/api/register', { method: 'POST', headers: { 'Content-Type': 'application/json' }, // 去掉多余的JSON.parse body: JSON.stringify({ username, password }) }).then((res) => res.json())
后端注册路由部分
首先确认你的express入口文件已添加解析JSON的中间件:
// app.js / index.js 入口文件添加 app.use(express.json())
修正后的注册路由:
router.post('/api/register', async (req, res) => { // 从请求体提取参数 const { username, password } = req.body if(!username || typeof username !== 'string'){ return res.json({status: 'error', error: 'Invalid username'}) } // 修正为校验password的类型 if(!password || typeof password !== 'string'){ return res.json({status: 'error', error: 'Invalid password'}) } // 修正长度判断逻辑,和提示一致要求至少6位 if (password.length < 6){ return res.json({ status: 'error', error: 'Password is too short. Password should at least have 6 characters.' }) } try { // 哈希后的密码使用新变量名,避免重复声明 const hashedPassword = await bcrypt.hash(password, 10) await User.create({ username, password: hashedPassword }) // 所有逻辑执行完成后再返回成功响应 res.json({status: 'ok'}) } catch (error) { // 先打印日志再处理错误 console.log(error) if (error.code === 11000){ return res.json({status: 'error', error: 'Username already in use'}) } // 兜底错误返回,避免抛出原生错误到前端 return res.json({status: 'error', error: 'Server internal error'}) } })
内容的提问来源于stack exchange,提问作者user17523218
相关产品推荐
相关产品推荐

