调用/api/v1/users/login接口报User模型_id的ObjectId转换错误如何修复
问题复现
调用 POST http://localhost:3000/api/v1/users/login 接口时抛出如下错误:
CastError: Cast to ObjectId failed for value "login" at path "_id" for model "User"
报错截图:
错误原因
Express 路由遵循从上到下的匹配规则,该错误是因为你将 /login 固定路径路由的定义,放在了带_id动态参数的用户路由(比如GET /:id、PUT /:id这类路由)的后面。当登录请求到达时,会先命中/:id动态路由规则,框架把路径中的login字符串当做_id参数传入,Mongoose 尝试将非ObjectId格式的login转为ObjectId类型失败,因此抛出报错。
修复方案
1. 调整路由定义顺序
将所有固定路径路由的定义,放在动态参数路由的前面即可,示例如下:
// 优先定义固定路径路由 router.post('/login', async (req,res) => { const user = await User.findOne({email: req.body.email}) const secret = process.env.secret; if(!user) { return res.status(400).send('The user not found'); } if(user && bcrypt.compareSync(req.body.password, user.passwordHash)) { const token = jwt.sign( { userId: user.id, isAdmin: user.isAdmin }, secret, {expiresIn : '1d'} ) res.status(200).send({user: user.email , token: token}) } else { res.status(400).send('password is wrong!'); } }) // 动态参数路由放在所有固定路径路由之后定义 router.get('/:id', async (req, res) => { // 根据id查询用户的原有逻辑 }) router.put('/:id', async (req, res) => { // 更新用户的原有逻辑 })
2. 可选优化:给动态路由加格式校验
可以给动态参数路由增加正则校验,只有参数符合24位十六进制的ObjectId格式时才匹配,避免被错误路径命中:
// 仅id为合法ObjectId格式时才会匹配该路由 router.get('/:id([a-fA-F0-9]{24})', async (req, res) => { // 原有逻辑 })
调整完成后重启服务,再次调用登录接口即可正常执行逻辑,不会再触发该报错。
内容的提问来源于stack exchange,提问作者my account
相关产品推荐
相关产品推荐

