【问题标题】:Express-js wildcard routing to cover everything under and including a pathExpress-js 通配符路由覆盖路径下的所有内容,包括路径
【发布时间】:2011-09-03 22:20:00
【问题描述】:

我试图让一条路线覆盖/foo 下的所有内容,包括/foo 本身。我试过使用/foo*,它适用于所有除了它不匹配/foo。观察:

var express = require("express"),
    app = express.createServer();

app.get("/foo*", function(req, res, next){
  res.write("Foo*\n");
  next();
});

app.get("/foo", function(req, res){
  res.end("Foo\n");
});

app.get("/foo/bar", function(req, res){
  res.end("Foo Bar\n");
});

app.listen(3000);

输出:

$ curl localhost:3000/foo
Foo
$ curl localhost:3000/foo/bar
Foo*
Foo Bar

我有哪些选择?我想出的最好的方法是路由/fo*,这当然不是很理想,因为它会匹配太多。

【问题讨论】:

  • 如果你拦截了所有/foo* 这样的路由,你不想让它成为中间件吗?
  • 小心你的要求:/foo* 匹配 /foo/bar,但也匹配 /foolish,这可能不是你想要的。

标签: node.js express


【解决方案1】:

对于正在学习node/express的人(就像我一样):尽可能不要使用通配符路由!

我还想使用通配符路由实现 GET /users/:id/whatever 的路由。我就是这样过来的。

更多信息:https://blog.praveen.science/wildcard-routing-is-an-anti-pattern/

【讨论】:

【解决方案2】:

没有必要有两条路线。

只需在 path 字符串的末尾添加 (/*)?

例如,app.get('/hello/world(/*)?' /* ... */)

这是一个完整的示例,您可以随意将其复制并粘贴到 .js 文件中以使用 node 运行,并在浏览器(或 curl)中使用它:

const app = require('express')()

// will be able to match all of the following
const test1 = 'http://localhost:3000/hello/world'
const test2 = 'http://localhost:3000/hello/world/'
const test3 = 'http://localhost:3000/hello/world/with/more/stuff'

// but fail at this one
const failTest = 'http://localhost:3000/foo/world'

app.get('/hello/world(/*)?', (req, res) => res.send(`
    This will match at example endpoints: <br><br>
    <pre><a href="${test1}">${test1}</a></pre>
    <pre><a href="${test2}">${test2}</a></pre>
    <pre><a href="${test3}">${test3}</a></pre>

    <br><br> Will NOT match at: <pre><a href="${failTest}">${failTest}</a></pre>
`))

app.listen(3000, () => console.log('Check this out in a browser at http://localhost:3000/hello/world!'))

【讨论】:

  • 我不知道为什么,但它对我不起作用。中间件:/template/:id(/*)? 父目录:/template/:id 子目录:/template/:id/edit 两个目录都会按预期触发,但中间件根本不会触发
  • 发现了...中间件router.use('/template/:id', ...) 将完美运行
【解决方案3】:

我认为你必须有 2 条路线。如果您查看连接路由器的第 331 行,路径中的 * 将替换为 .+,因此将匹配 1 个或多个字符。

https://github.com/senchalabs/connect/blob/master/lib/middleware/router.js

如果您有 2 条路线执行相同的操作,您可以执行以下操作以保留它DRY

var express = require("express"),
    app = express.createServer();

function fooRoute(req, res, next) {
  res.end("Foo Route\n");
}

app.get("/foo*", fooRoute);
app.get("/foo", fooRoute);

app.listen(3000);

【讨论】:

  • app.get(["/foo", "/foo*"], /* function */); 可能也有优惠!
  • 传入一个字符串数组对我来说也是优先的。不幸的是:将数组传递给 app.VERB() 已被弃用,并将在 4.0 中删除
  • 在 Express 4.9.1 中恢复了传入字符串数组。
【解决方案4】:

在数组中你也可以使用传递给 req.params 的变量:

app.get(["/:foo", "/:foo/:bar"], /* function */);

【讨论】:

    【解决方案5】:

    connect 路由器现已被移除 (https://github.com/senchalabs/connect/issues/262),作者指出您应该在 connect 之上使用框架(如 Express)进行路由。

    currently treatsapp.get("/foo*") 表达为app.get(/\/foo(.*)/),不再需要两条单独的路线。这与之前的答案(指现在删除的连接路由器)形成对比,后者指出“路径中的* 替换为.+”。

    更新: Express 现在使用“path-to-regexp”模块(自 Express 4.0.0 起),该模块在当前引用的版本中维护 the same behavior。我不清楚该模块的最新版本是否保留了这种行为,但目前这个答案是有效的。

    【讨论】:

    • 那么我们应该使用 .+ 还是 *?
    • 如果您想匹配/foo 后跟一个或多个字符,请使用/\/foo(.+)/,如果您想匹配/foo 后跟零个或多个字符,请使用/foo*/\/foo(.*)/
    • “在当前引用的版本中”非常模糊,“现在”也是如此。这个答案非常令人困惑。
    猜你喜欢
    • 2013-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-23
    • 1970-01-01
    • 2016-04-11
    • 2022-01-04
    • 2013-03-25
    相关资源
    最近更新 更多