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



我即将在 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

我正在努力弄清楚如何在不让参数变得self的情况下使用这种模式:user_id{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))

你可以做些什么来创建条件路由中间件。工厂 dunction 将确定应使用哪个路由器的回调方法作为第一个参数,将路由器列表作为第二个参数,并返回有条件地使用其中一个路由的新中间战争。

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)
])

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

最新更新