Express.js 路由:可选的 splat 参数?
Posted
技术标签:
【中文标题】Express.js 路由:可选的 splat 参数?【英文标题】:Express.js routing: optional splat param? 【发布时间】:2012-04-18 16:35:13 【问题描述】:我的路线如下所示:
app.all('/path/:namedParam/*splat?',function(req,res,next)
if(!req.params.length)
// do something when there is no splat
else
// do something with splat
);
但是,这不起作用 - 如果我调用 path/foo/bar
,它会到达路线,但如果我调用 path/foo
,它不会。
是否可以有一个可选的 splat 参数,或者我必须使用正则表达式来检测这个?
编辑:
为了更清楚,这里是我想要达到的要求:
第一个和第二个参数是必需的 第一个参数是静态的,第二个是命名参数。 可以附加任意数量的可选额外参数,并且仍然可以访问路由。【问题讨论】:
你想做什么?如果您不需要了解 splat,只需执行'/path/:firstParam/*'
。如果需要,请'/path/:firstParam/:secondParam?/*'
。
我希望 splat 是可选的 - 您给出的第一个示例与 /path/foo
不匹配,(在我想要一个可选的 splat 之前,我的路线最初看起来像这样)。此外,在您的第二个示例中,添加 splat 实际上会否定可选的第二个参数 - /path/foo
不会匹配您的第二个模式(/path/foo/bar
也不会...) - express 路由器中更烦人的部分之一.
就我个人而言,我会选择 /path/:firstParam
和 /path/:firstParam/:secondParam/
作为两个独立的路由器,共享控制器。无需让您的网址混乱
拥有n
端点对于应用程序的设计是必要的 - 我不只是路由到 1-3 个参数,它可以是任何数字,因此对参数数量有限制不是一个选项(当然,我可以创建 10 个端点,但是让 express 做这项工作并不比在路线中做更好)。我可以使用正则表达式路由来解决我的问题(我现在正在做的事情),但我希望有一个可读的选项。
令人惊讶的是,开发人员并没有想到简单地使用括号来命名可选参数。即/path/:param(/:otherOptionalParam)
【参考方案1】:
这适用于 express 4 上的 /path 和 /path/foo,请注意 *
之前的 ?
。
router.get('/path/:id*?', function(req, res, next)
res.render('page', title: req.params.id );
);
【讨论】:
请注意,虽然这确实有效,但如果您访问/path/foo/bar/bazzle
,req.params.id
将等于foo
,req.params[0]
将等于/bar/bazzle
,这可能会使一些人绊倒。更简洁的解决方案可能是将路径定义为 /path/*?
,在 express 4 中将 req.params[0]
设置为 foo/bar/bazzle
,这可能更接近您要查找的内容。
你最好对你的可选参数进行 url 编码 - 允许任何带有斜杠的东西意味着如果你想添加类似 app.get('path/:required1/ 这样的路径,你将在路上遇到冲突:required2/:optional?*', handler)
@Jesse 有什么方法可以使最后一部分成为必需的吗?例如,我想匹配/path/foo/bar
但不 /path/foo
。我试过'/path/:id/*
但*
似乎也匹配空字符串。【参考方案2】:
我刚刚遇到同样的问题并解决了。这是我用的:
app.get('path/:required/:optional*?', ...)
这应该适用于path/meow
、path/meow/voof
、path/meow/voof/moo/etc
...
似乎通过在?
和*
之间删除/
,最后一个/
也成为可选的,而:optional?
仍然是可选的。
【讨论】:
酷!我刚刚测试了这个(在 express 3.0.0 中,没有在 2.x 中测试)并且它有效。这绝对比我的 RegEx hack 更干净。 你知道我可以在哪里阅读更多关于这些预定义关键字的信息吗? 在 express 4.0x 中这似乎不再起作用 @chris 为 express 4 回答了这个问题 - 因为这是最新的,所以我将接受的答案移至他的。 使用这个遇到了一个奇怪的错误,对于其中包含零的数字,快递将把它切断。例如 /:id where id=904, req.params.id = 9 and req.params.0=04 (出于某种原因,这里将其余部分快速转储)。克里斯的回答解决了这个问题【参考方案3】:这会做你所追求的吗?
app.all('/path/:namedParam/:optionalParam?',function(req,res,next)
if(!req.params.optionalParam)
// do something when there is no optionalParam
else
// do something with optionalParam
);
更多关于 Express 路由的信息,如果你还没有看过的话:http://expressjs.com/guide/routing.html
【讨论】:
此解决方案将匹配/path/foo/bar
,但不匹配 /path/foo/bar/baz
- *
splat 匹配 .+
,这对于我正在做的事情是必要的 - 我肯定是 rtfm,不好像没提过,所以也许不可能……【参考方案4】:
这是我解决此问题的当前方法,似乎 express 不支持任意数量的带有可选命名参数的 splat 参数:
app.all(/\/path\/([^\/]+)\/?(.+)?/,function(req,res,next)
// Note: this is all hacked together because express does not appear to support optional splats.
var params = req.params[1] ? [req.params[1]] : [],
name = req.params[0];
if(!params.length)
// do something when there is no splat
else
// do something with splat
);
为了可读性和一致性,我很乐意将此使用命名为 params - 如果出现另一个允许这样做的答案,我会接受它。
【讨论】:
【参考方案5】:假设你有这个网址:/api/readFile/c:/a/a.txt
如果您希望 req.params.path
成为 c:
:
'/api/readFile/:path*
如果您希望 req.params.path
成为 c:/a/a.txt
:
'/api/readFile/:path([^/]*)'
【讨论】:
【参考方案6】:上述使用可选的解决方案在 Express 4 中不起作用。我尝试了几种使用搜索模式的方法,但也不起作用。然后我找到了这个方法,似乎被无限嵌套路径解雇了,http://expressjs.com/api.html#router
// this will only be invoked if the path starts with /bar from the mount point
router.use('/bar', function(req, res, next)
// ... maybe some additional /bar logging ...
// to get the url after bar, you can try
var filepath = req.originalUrl.replace(req.baseUrl, "");
next();
);
它匹配所有/bar,/bar/z,/bar/a/b/c 等。然后,您可以阅读req.originalUrl,因为参数未填充,例如。您可以尝试比较 baseUrl 和 originalUrl 以获取剩余路径。
【讨论】:
【参考方案7】:我通过使用在 url 和router.get('/bar/*?', ...
中添加斜杠的中间件的组合解决了这个问题,它将拾取/bar/
之后的所有内容,如果它只是/bar/
,则返回undefined
。如果访问者请求/bar
,express-slash
中间件将在请求中添加一个斜线并将请求转换为/bar/
。
【讨论】:
以上是关于Express.js 路由:可选的 splat 参数?的主要内容,如果未能解决你的问题,请参考以下文章