You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)

  1. 路由第一行就执行了res.json({status: 'ok'}),直接返回了响应,后续所有注册逻辑完全不会执行,且后续尝试再次返回res.json会触发重复返回响应的报错。
  2. 没有从请求体中提取username和password变量,直接使用未定义的变量会触发运行时报错。
  3. 密码校验逻辑写错:if(!password || typeof username !== 'string')这里错误校验了username的类型,没有校验密码的类型。
  4. 重复声明password变量:后续使用const password = await bcrypt.hash(...)会和前面的password变量冲突,触发变量重复声明报错。
  5. 密码长度校验逻辑不匹配:判断条件是password.length < 5,但错误提示要求至少6位,逻辑不一致。
  6. catch块执行顺序错误:先执行throw error再打印日志,打印代码永远不会执行;且抛出错误没有做兜底返回,前端接收到的是非JSON格式的报错内容。
  7. 额外需要确认:你的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 20:15:02