Routing z symbolami wieloznacznymi Express-js obejmujący wszystko, co znajduje się pod ścieżką i łącznie z nią

96

Staram się, aby jedna trasa obejmowała wszystko, w /footym /foosiebie. Próbowałem użyć tej /foo*pracy do wszystkiego, z wyjątkiem tego, że nie pasuje /foo. Przestrzegać:

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

Wyjścia:

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

Jakie mam możliwości? Najlepsze, co wymyśliłem, to trasa, /fo*która oczywiście nie jest zbyt optymalna, ponieważ pasowałaby o wiele za dużo.

Kit Sunde
źródło
Jeśli przechwytujesz wszystkie /foo*takie trasy, nie chcesz zamiast tego uczynić go oprogramowaniem pośredniczącym?
Raynos
3
Uważaj, o co prosisz: /foo*mecze, /foo/barale także mecze, /foolishktórych prawdopodobnie nie zamierzałeś.
Wyck

Odpowiedzi:

112

Myślę, że będziesz musiał mieć 2 trasy. Jeśli spojrzysz na linię 331 routera połączeniowego, * w ścieżce zostanie zastąpione przez. +, Więc dopasuje 1 lub więcej znaków.

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

Jeśli masz 2 trasy, które wykonują tę samą akcję, możesz wykonać następujące czynności, aby zachować je SUCHA .

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
źródło
103
app.get(["/foo", "/foo*"], /* function */);może być również preferencyjne!
Chris Foster,
9
Mnie też preferencyjne jest przekazywanie szeregu strun. Niestety: przekazywanie tablicy do app.VERB () jest przestarzałe i zostanie usunięte w wersji 4.0
CodeWarrior
10
Podawanie tablicy ciągów zostało przywrócone w Express 4.9.1.
Pete TNT
30

Router connect został teraz usunięty ( https://github.com/senchalabs/connect/issues/262 ), a autor stwierdził, że do routingu należy używać frameworka na górze connect (jak Express).

Express obecnie traktuje app.get("/foo*") jako app.get(/\/foo(.*)/), eliminując potrzebę dwóch oddzielnych tras. Kontrastuje to z poprzednią odpowiedzią (odnoszącą się do usuniętego routera connect), w której stwierdzono, że „ *ścieżka jest zastępowana przez .+”.

Aktualizacja: Express używa teraz modułu „path-to-regexp” (od wersji Express 4.0.0), który zachowuje to samo zachowanie w wersji, do której się obecnie odwołuje. Nie jest dla mnie jasne, czy najnowsza wersja tego modułu zachowuje to zachowanie, ale na razie ta odpowiedź jest aktualna.

Johann
źródło
Powinniśmy więc użyć. + Lub *?
Tyler Langan
2
Użyj, /\/foo(.+)/jeśli chcesz dopasować, /foopo którym następuje jeden lub więcej znaków, /foo*lub /\/foo(.*)/jeśli chcesz dopasować, /fooa następnie zero lub więcej znaków.
Johann
12

Nie jest konieczne posiadanie dwóch tras.

Po prostu dodaj (/*)?na końcu swojego pathciągu.

Na przykład, app.get('/hello/world(/*)?' /* ... */)

Oto w pełni działający przykład, możesz go skopiować i wkleić do pliku .js, aby uruchomić go z węzłem, i bawić się nim w przeglądarce (lub 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.
źródło
9

W tablicy możesz również użyć zmiennych przekazujących do req.params:

app.get(["/:foo", "/:foo/:bar"], /* function */);
DrDimedrol
źródło
4

Dla tych, którzy uczą się węzłów / ekspresów (tak jak ja): nie używaj routingu symboli wieloznacznych, jeśli to możliwe!

Chciałem również zaimplementować routing dla GET / users /: id / cokolwiek za pomocą routingu wieloznacznego. Tak się tu dostałem.

Więcej informacji: https://blog.praveen.science/wildcard-routing-is-an-anti-pattern/

throbi
źródło
3
Link obecnie nie żyje. Być może było to to samo, co: jonathanong.github.io/wildcard-routing-is-an-anti-pattern.html
Ron Burk.
@RonBurk Twój adres URL również wydaje się być martwy. Jak mogę mieć opcjonalny symbol wieloznaczny po nazwanym parametrze? „/ coś /: id (/ *)?” nie działa ..
Soichi Hayashi
Prawdopodobnie jeszcze przez chwilę będzie w pamięci podręcznej Google: webcache.googleusercontent.com/…
Ron Burk,
Czy istnieje alternatywa dla routingu symboli wieloznacznych, jeśli nie mam pojęcia, co następuje po początkowej części adresu URL?
Michael,
2
Oto ponownie opublikowany: Routing Wildcard is an Anti-Pattern
Praveen Kumar Purushothaman