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/bazzlereq.params.id 将等于fooreq.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/meowpath/meow/voofpath/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。如果访问者请求/barexpress-slash 中间件将在请求中添加一个斜线并将请求转换为/bar/

【讨论】:

以上是关于Express.js 路由:可选的 splat 参数?的主要内容,如果未能解决你的问题,请参考以下文章

可选的反应路由器参数标记 GET 请求错误?

可选的反应路由器参数

angularjs 路由可以有可选的参数值吗?

typescript 可选的路由参数

typescript 可选的路由参数

如何使用可选的查询字符串参数测试 MVC 路由