Express.js中间件静态类型的路径和具有参数冲突的路径

时间:2018-08-21 08:26:11

标签: javascript node.js rest express

我将在expressjs中为经过身份验证的用户和未经身份验证的用户实现REST端点。我目前对REST的了解使我采用了以下设计模式:

用户资源

令牌用户:

/users/self GET, PATCH

非令牌用户:

/users POST

/users/:user_id GET

个人资料图片资源

令牌用户:

/users/self/profile-images POST

/users/self/profile-images/:profile_image_id PUT, DELETE

非令牌用户:

/users/:user_id/profile-images GET

我正在努力弄清楚如何在不使:user_id参数(即self)变为{user_id: 'self'}的情况下使用此模式。我希望它们充当两种不受干扰的隔离路径类型,一种严格,一种动态。这可能吗?如果可以,怎么办?

当前实现的代码示例如下:

// instPrivateUserRestRoutes.js (token-user)
router.use('/users/self', [
  instAccountRestRoutes(restControllers),
  instAuthenticationSessionRestRoutes(restControllers),
  instPrivateProfileImageRestRoutes(restControllers)
])

// instPublicUserRestRoutes.js (non-token user)
router.use('/users/:user_id', [
  instPublicProfileImageRestRoutes(restControllers)
])

// instRestApp.js (mount point for top resources)
router.use(instPrivateUserRestRoutes(restControllers))
router.use(instPublicUserRestRoutes(restControllers))

1 个答案:

答案 0 :(得分:0)

如何创建条件路由中间件。工厂用法将决定使用哪个路由器的回调方法作为第一个参数,将路由器列表作为第二个参数,并返回一个新的中间战争,有条件地使用其中一条路由。

function conditionalRouting(cond, routes) {
  return function (req, res, next) {
    try{
      // get the index for the router that should be used
      var idx = cond(req, res)

      // call this router and pass req, res and next to it
      routes[idx](req, res, next)
    } catch(err) {
      // in the case an error occurs in on of the steps "throw" that error
      next(err)
    }
  } 
}

然后您可以使用这种方式:

app.use(
    '/users/:user_id',
    conditionalRouting(
      (req, _) => req.params.user_id === 'self' ? 0:1,
      [routerForSelf, routerForUser]
    ))

另一种方法是使用触发未发现错误的中间件显式处理这种情况:

function forceNotFound(req, res, next) {
    var error = new Error('resource not found')
    error.status = 404
    next(error)
}

并将其添加为您的最后一个中间件

router.use('/users/self', [
  instAccountRestRoutes(restControllers),
  instAuthenticationSessionRestRoutes(restControllers),
  instPrivateProfileImageRestRoutes(restControllers),
  forceNotFound
])

这种方式很明显,快递应该在那一点上停止。

这看起来与标准Cannot GET /the/path的外观不同,但是您通常还是不想显示这些默认错误消息。

如果您希望收到相同类型的消息,则可以编写:

var parseUrl = require('parseurl')
var encodeUrl = require('encodeurl')

app.use((req, res, next) => {
    var msg = 'Cannot ' + req.method + ' ' + encodeUrl(parseUrl.original(req).pathname)
    var error = new Error(msg)
    error.status = 404
    next(error)
})

如果您只想处理数字ID,则可以使用以下方法:

router.use('/users/:user_id(\\d+)', [
  instPublicProfileImageRestRoutes(restControllers)
])

只有当instPublicProfileImageRestRoutes是数字时,才会调用user_id