快递空 req.params 路线到上一条路线

Express empty req.params route to the previous route

假设我有以下 REST 端点

/api/companies
/api/companies/:id
/api/companies/name/:slug

第一个路由 /api/companies POST 将 post 一个新公司,而 GET 将获取所有公司的列表。

第二条路线 /api/companies/:id GET 将通过其 id 获取该特定公司,PUT 将更新它,DELETE 将其删除。

第三条路线/api/companies/name/:slug将获取以name开头的公司列表。

我的 router.js 文件看起来像这样

// /api/companies
router
    .route('/')
    .post(controllers.createCompany)
    .get(controllers.getByPriority)

// /api/companies/:id
router
    .route('/:id')
    .put(controllers.updateOne)
    .delete(controllers.removeOne)
    .get(controllers.getOne)

// /api/companies/name/:slug
router
    .route('/name/:slug?')
    .get(controllers.getByName)

问题是如果第三条路由中没有slug参数,它将与第二条路由匹配,这将return投射错误。

例如:GET /api/companies/name/ return出现以下错误

CastError: Cast to ObjectId failed for value "name" (type string) at path "_id" for model "company"
    at model.Query.exec (D:\Projects\StackInfo\stack-info\backend\node_modules\mongoose\lib\query.js:4545:21)
    at D:\Projects\StackInfo\stack-info\backend\dist\utils\crud.js:91:15
    at Layer.handle [as handle_request] (D:\Projects\StackInfo\stack-info\backend\node_modules\express\lib\router\layer.js:95:5)
    at next (D:\Projects\StackInfo\stack-info\backend\node_modules\express\lib\router\route.js:137:13)
    at next (D:\Projects\StackInfo\stack-info\backend\node_modules\express\lib\router\route.js:131:14)
    at next (D:\Projects\StackInfo\stack-info\backend\node_modules\express\lib\router\route.js:131:14)
    at next (D:\Projects\StackInfo\stack-info\backend\node_modules\express\lib\router\route.js:131:14)
    at next (D:\Projects\StackInfo\stack-info\backend\node_modules\express\lib\router\route.js:131:14)
    at next (D:\Projects\StackInfo\stack-info\backend\node_modules\express\lib\router\route.js:131:14)
    at next (D:\Projects\StackInfo\stack-info\backend\node_modules\express\lib\router\route.js:131:14) {
  messageFormat: undefined,
  stringValue: '"name"',
  kind: 'ObjectId',
  value: 'name',
  path: '_id',
  reason: TypeError: Argument passed in must be a Buffer or string of 12 bytes or a string of 24 hex characters
      at new BSONTypeError (D:\Projects\StackInfo\stack-info\backend\node_modules\bson\lib\error.js:39:42)
      at new ObjectId (D:\Projects\StackInfo\stack-info\backend\node_modules\bson\lib\objectid.js:62:23)
      at castObjectId (D:\Projects\StackInfo\stack-info\backend\node_modules\mongoose\lib\cast\objectid.js:25:12)
      at ObjectId.cast (D:\Projects\StackInfo\stack-info\backend\node_modules\mongoose\lib\schema\objectid.js:245:12)
      at ObjectId.SchemaType.applySetters (D:\Projects\StackInfo\stack-info\backend\node_modules\mongoose\lib\schematype.js:1135:12)
      at ObjectId.SchemaType._castForQuery (D:\Projects\StackInfo\stack-info\backend\node_modules\mongoose\lib\schematype.js:1567:15)
      at ObjectId.SchemaType.castForQuery (D:\Projects\StackInfo\stack-info\backend\node_modules\mongoose\lib\schematype.js:1557:15)
      at ObjectId.SchemaType.castForQueryWrapper (D:\Projects\StackInfo\stack-info\backend\node_modules\mongoose\lib\schematype.js:1534:20)
      at cast (D:\Projects\StackInfo\stack-info\backend\node_modules\mongoose\lib\cast.js:336:32)
      at model.Query.Query.cast (D:\Projects\StackInfo\stack-info\backend\node_modules\mongoose\lib\query.js:4968:12),
  valueType: 'string'
}

crud.js getOne 看起来也是这样

export const getOne = model => async (req, res) => {
    try {
        const id = req.params.id
        const doc = await model
            .findOne({ _id: id })
            .lean().exec() // Where the error exists
        if (!doc) {
            return res.status(404).end()
        }
        res.status(200).json({ data: doc })
    } catch (e) {
        console.error(e)
        res.status(400).end()
    }
}

我尝试添加其他路由,以便在没有传递 slug 的情况下处理请求

// /api/companies
router
    .route('/')
    .post(controllers.createCompany)
    .get(controllers.getByPriority)

// /api/companies/:id
router
    .route('/:id')
    .put(controllers.updateOne)
    .delete(controllers.removeOne)
    .get(controllers.getOne)

// in case /api/companies/name/:slug did not match
router
.route('/name')
.get(controllers.getByPriority)
// /api/companies/name/:slug
router
    .route('/name/:slug?')
    .get(controllers.getByName)

但它仍然与 /api/companies/:id 路由匹配并且 return 出现相同的错误。那么,当我在 /api/companies/name/ 上请求时,即使参数为空,是否有任何解决方案可以避免使用 /api/companies/:id 进行路由?

从上到下表达执行代码。所以你可以在代码中颠倒端点的顺序。由于/name/:slug比较具体,所以在/:id之前定义:

router
    .route('/')
    .post(controllers.createCompany)
    .get(controllers.getByPriority)

router
    .route('/name/:slug?')
    .get(controllers.getByName)

router
    .route('/:id')
    .put(controllers.updateOne)
    .delete(controllers.removeOne)
    .get(controllers.getOne)