什么是Mongoose错误对于path“_id”中的值XXX,转换为ObjectId失败?

当向/customers/41224d776a326fb40f000001发送请求并且_id 41224d776a326fb40f000001文档不存在时, docnull并且返回404

  Controller.prototype.show = function(id, res) { this.model.findById(id, function(err, doc) { if (err) { throw err; } if (!doc) { res.send(404); } return res.send(doc); }); }; 

然而,当_id不匹配Mongoose所期望的“格式”(我想)例如GET /customers/foo会返回一个奇怪的错误:

CastError:在path“_id”上投射到ObjectId的值“foo”失败。

那么这个错误是什么?

Mongoose的findById方法将id参数转换为模型_id字段的types,以便它可以正确查询匹配的文档。 这是一个ObjectId,但"foo"不是一个有效的ObjectId,因此转换失败。

这不会发生41224d776a326fb40f000001因为该string是一个有效的ObjectId。

解决这个问题的一个方法是在findById调用之前添加一个检查来查看id是否是一个有效的ObjectId或者不是这样:

 if (id.match(/^[0-9a-fA-F]{24}$/)) { // Yes, it's a valid ObjectId, proceed with `findById` call. } 

使用现有的函数来检查ObjectID。

 var mongoose = require('mongoose'); mongoose.Types.ObjectId.isValid('your id here'); 

你parsing那个string为ObjectId

在我的应用程序中,我所做的是:

 ObjectId.fromString( myObjectIdString ); 

你也可以像下面这样使用ObjectId.isValid:

 if (!ObjectId.isValid(userId)) return Error({ status: 422 }) 

我采用了@gustavohenke解决scheme的一种改进, 在原始代码中包装的try-catch中实现强制转换ObjectId,以利用ObjectId强制转换作为validation方法的失败。

 Controller.prototype.show = function(id, res) { try { var _id = mongoose.Types.ObjectId.fromString(id); // the original code stays the same, with _id instead of id: this.model.findById(_id, function(err, doc) { if (err) { throw err; } if (!doc) { res.send(404); } return res.send(doc); }); } catch (err) { res.json(404, err); } }; 

或者你可以做到这一点

var ObjectId = require('mongoose').Types.ObjectId; var objId = new ObjectId( (param.length < 12) ? "123456789012" : param );

就像这里提到的Mongoose的$或者condition的find方法不能正常工作

这是一个老问题,但你也可以使用express-validator包来检查请求参数

express-validator版本4(最新):

 validator = require('express-validator/check'); app.get('/show/:id', [ validator.param('id').isMongoId().trim() ], function(req, res) { // validation result var errors = validator.validationResult(req); // check if there are errors if ( !errors.isEmpty() ) { return res.send('404'); } // else model.findById(req.params.id, function(err, doc) { return res.send(doc); }); }); 

expressionvalidation器版本3:

 var expressValidator = require('express-validator'); app.use(expressValidator(middlewareOptions)); app.get('/show/:id', function(req, res, next) { req.checkParams('id').isMongoId(); // validation result req.getValidationResult().then(function(result) { // check if there are errors if ( !result.isEmpty() ) { return res.send('404'); } // else model.findById(req.params.id, function(err, doc) { return res.send(doc); }); }); });