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

Sequelize findOne返回值及Pokemon创建存在性验证故障排查

问题:新增Pokemon时重复数据处理异常

问题现象

我要做一个新增Pokemon的控制器,逻辑是先检查PostgreSQL数据库里有没有同名Pokemon,有就返回错误,没有就创建。现在用Insomnia发POST请求时,Pokemon不存在能正常创建并返回提示;但如果已存在,客户端会收到“创建成功”的提示,数据库没新增数据,而且服务器直接崩溃。我需要实现:存在同名Pokemon时,客户端能看到错误提示,同时服务器不崩溃。怀疑是不是该在路由层做验证,或者不能用throw new Error。

控制器代码

const { Pokemon } = require('../db')

const postPokemon = async (name, health, attak, def, speed, height, weight) => {
    const search = await Pokemon.findOne({ where: { name }})
    if(search !== null){
        throw new Error(`Ya existe un pokemon con el nombre ${name}`)
    } else{
        const createPokemon = await Pokemon.create({name, health, attak, def, speed, height, weight})

        return createPokemon
    } 
}

module.exports = {
    postPokemon
}

路由代码

pokemonsRouter.post('/', async (req, res) => {
    
    try {
        const { name, health, attak, def, speed, height, weight } = req.body
        if(!name) throw new Error(`El campo nombre no puede estar vacio`)
        postPokemon(name, health, attak, def, speed, height, weight)
        res.status(200).send(`El pokemon ${name} fue creado correctamente`)
    } catch (error) {
        res.status(400).send(error.message)
    }
})

错误日志

pokemon-main\api\src\controllers\postPokemons.js:6
        throw new Error(`Ya existe un pokemon con el nombre ${name}`)
              ^

     Error: Ya existe un pokemon con el nombre Charmander
      at postPokemon (C:\Users\crist\OneDrive\Escritorio\hc\PIs\PI-Pokemon-main\PI-Pokemon-main\api\src\controllers\postPokemons.js:6:15)
     at processTicksAndRejections (node:internal/process/task_queues:96:5)
    [nodemon] app crashed - waiting for file changes before starting...

Sequelize官方findOne示例(中文翻译)

const project = await Project.findOne({ where: { title: 'My Title' } });
if (project === null) {
   console.log('未找到!');
} else {
      console.log(project instanceof Project); // true
      console.log(project.title); // 'My Title'
}

问题原因及修复方案

核心问题

  1. 路由未等待异步函数执行:postPokemon是异步函数,但路由调用时没加await,导致控制器逻辑还没跑完,就直接返回了“创建成功”的响应。
  2. 异步错误未被捕获:因为没加await,控制器抛出的错误会变成未捕获的Promise拒绝,直接导致服务器崩溃。

修复步骤

1. 路由层添加await,等待控制器执行结果

修改路由代码,确保等待控制器完成后再处理响应:

pokemonsRouter.post('/', async (req, res) => {
    
    try {
        const { name, health, attak, def, speed, height, weight } = req.body
        if(!name) throw new Error(`El campo nombre no puede estar vacio`)
        // 加上await,等待控制器执行完成
        await postPokemon(name, health, attak, def, speed, height, weight)
        // 创建成功用201状态码更符合REST规范
        res.status(201).send(`El pokemon ${name} fue creado correctamente`)
    } catch (error) {
        res.status(400).send(error.message)
    }
})

2. 控制器错误处理可选方案

方案一:保持抛出错误的方式

控制器代码不变,因为路由已经加了await,抛出的错误会被try/catch捕获,返回给客户端错误提示,服务器不会崩溃。

方案二:返回错误字符串替代抛出

如果不想用throw,可以让控制器返回错误字符串,路由根据返回值判断:

// 控制器代码修改
const postPokemon = async (name, health, attak, def, speed, height, weight) => {
    const search = await Pokemon.findOne({ where: { name }})
    if(search !== null){
        return `Ya existe un pokemon con el nombre ${name}`
    } else{
        return await Pokemon.create({name, health, attak, def, speed, height, weight})
    } 
}

// 路由对应修改
pokemonsRouter.post('/', async (req, res) => {
    try {
        const { name, health, attak, def, speed, height, weight } = req.body
        if(!name) throw new Error(`El campo nombre no puede estar vacio`)
        const result = await postPokemon(name, health, attak, def, speed, height, weight)
        if (typeof result === 'string') {
            res.status(400).send(result)
        } else {
            res.status(201).send(`El pokemon ${name} fue creado correctamente`)
        }
    } catch (error) {
        res.status(400).send(error.message)
    }
})

额外优化建议

给Pokemon模型的name字段添加唯一约束,双重保障避免重复数据:

// 在Pokemon模型定义中修改name字段
name: {
    type: DataTypes.STRING,
    allowNull: false,
    unique: true // 添加唯一约束
}

这样即使代码层面验证失效,数据库也会拒绝插入重复数据,此时可以捕获Sequelize的唯一约束错误,返回更友好的提示。

内容的提问来源于stack exchange,提问作者Frank

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 14:25:24