Routage générique Express-js pour tout couvrir sous et y compris un chemin

96

J'essaie d'avoir une route couvrant tout, /fooy compris /foolui-même. J'ai essayé d'utiliser /foo*quel travail pour tout sauf qu'il ne correspond pas /foo. Observer:

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

Les sorties:

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

Quelles sont mes options? Le mieux que j'ai trouvé est de tracer /fo*ce qui, bien sûr, n'est pas très optimal car cela correspondrait beaucoup trop.

Kit Sunde
la source
Si vous interceptez toutes les /foo*routes comme ça, ne voulez-vous pas en faire un middleware à la place?
Raynos
3
Faites attention à ce que vous demandez: des /foo*matchs /foo/barmais aussi des matchs /foolishauxquels vous n'aviez probablement pas l'intention.
Wyck

Réponses:

111

Je pense que vous devrez avoir 2 itinéraires. Si vous regardez la ligne 331 du routeur de connexion, le * dans un chemin est remplacé par. + Donc correspondra à 1 ou plusieurs caractères.

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

Si vous avez 2 itinéraires qui effectuent la même action, vous pouvez faire ce qui suit pour le garder SEC .

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);
serby
la source
101
app.get(["/foo", "/foo*"], /* function */);pourrait être préférentiel aussi!
Chris Foster
9
Passer un tableau de chaînes est également préférable pour moi. Malheureusement: passer un tableau à app.VERB () est obsolète et sera supprimé dans la version 4.0
CodeWarrior
10
La transmission d'un tableau de chaînes a été restaurée dans Express 4.9.1.
Pete TNT
30

Le routeur de connexion a maintenant été supprimé ( https://github.com/senchalabs/connect/issues/262 ), l'auteur déclarant que vous devez utiliser un framework au-dessus de connect (comme Express) pour le routage.

Express traite actuellement app.get("/foo*") comme app.get(/\/foo(.*)/), supprimant le besoin de deux itinéraires distincts. Ceci est en contraste avec la réponse précédente (faisant référence au routeur de connexion maintenant supprimé) qui déclarait que " *dans un chemin est remplacé par .+".

Mise à jour: Express utilise désormais le module "path-to-regexp" (depuis Express 4.0.0) qui conserve le même comportement dans la version actuellement référencée. Je ne sais pas si la dernière version de ce module conserve le comportement, mais pour l'instant, cette réponse est valable.

Johann
la source
Alors devrions-nous utiliser. + Ou *?
Tyler Langan
2
À utiliser /\/foo(.+)/si vous voulez faire correspondre /foosuivi d'un ou plusieurs caractères, et /foo*ou /\/foo(.*)/si vous voulez faire correspondre /foosuivi de zéro ou plusieurs caractères.
Johann
12

Il n'est pas nécessaire d'avoir deux itinéraires.

Ajoutez simplement (/*)?à la fin de votre pathchaîne.

Par exemple, app.get('/hello/world(/*)?' /* ... */)

Voici un exemple entièrement fonctionnel, n'hésitez pas à copier et coller ceci dans un fichier .js à exécuter avec node, et à jouer avec dans un navigateur (ou 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!'))
Somo S.
la source
9

Dans le tableau, vous pouvez également utiliser des variables passant à req.params:

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

Pour ceux qui apprennent node / express (tout comme moi): n'utilisez pas le routage générique si possible!

Je voulais également implémenter le routage pour GET / users /: id / tout en utilisant le routage générique. Voilà comment je suis arrivé ici.

Heureusement, j'ai aussi trouvé cet article: http://www.jongleberry.com/wildcard-routing-is-an-anti-pattern.html

Bravo, Robert

throbi
la source
2
Lien actuellement mort. C'était peut-être la même chose que: jonathanong.github.io/wildcard-routing-is-an-anti-pattern.html
Ron Burk
@RonBurk votre URL semble également être morte. Comment puis-je avoir un caractère générique facultatif après un paramètre nommé? "/ quelque chose /: id (/ *)?" ne fonctionne pas ..
Soichi Hayashi
Sera
Ron Burk
existe-t-il une alternative au routage générique si je n'ai aucune idée de ce qui vient après la partie initiale de l'URL?
Michael
1
Voici celui qui a été republié: Wildcard Routing is an Anti-Pattern
Praveen Kumar Purushothaman