Routing Express.js: opcjonalny parametr splat?

82

Mam trasę, która wygląda tak:

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

jednak to nie działa - jeśli nazywam path/foo/barto trafia w trasę, ale jeśli dzwonię path/foo, nie działa.

Czy można mieć opcjonalny parametr splat, czy też muszę użyć wyrażenia regularnego, aby to wykryć?

Edycja :

żeby było jaśniej, oto wymagania, które staram się osiągnąć:

  • wymagany jest pierwszy i drugi parametr
  • pierwszy parametr jest statyczny, drugi to nazwany parametr.
  • dowolna liczba opcjonalnych dodatkowych parametrów może być dołączona i nadal trafia na trasę.
Jesse
źródło
1
co próbujesz zrobić? jeśli nie potrzebujesz znać Splata, po prostu zrób '/path/:firstParam/*'. Jeśli tego potrzebujesz, zrób '/path/:firstParam/:secondParam?/*'.
Jonathan Ong,
1
Chcę, aby ikona była opcjonalna - pierwszy przykład, który podałeś, nie pasowałby /path/foo(tak pierwotnie wyglądała moja trasa, zanim chciałem opcjonalnej ikony). Dodatkowo, w twoim drugim przykładzie, dodanie ikony faktycznie neguje opcjonalny drugi parametr - /path/foonie będzie pasował do twojego drugiego wzorca ( tak samo nie będzie /path/foo/bar...) - jedna z bardziej irytujących części routera Express.
Jesse,
1
Osobiście po prostu wybrałbym /path/:firstParami /path/:firstParam/:secondParam/jako dwa oddzielne routery ze wspólnym kontrolerem. nie ma potrzeby, aby Twoje adresy URL były mylące
Jonathan Ong,
Posiadanie npunktów końcowych jest konieczne do zaprojektowania aplikacji - nie kieruję się tylko do 1-3 parametrów, może to być dowolna liczba, więc ograniczenie liczby parametrów nie wchodzi w grę (jasne, mógłbym utworzyć 10 punktów końcowych, ale praca ekspresowa nie jest lepsza niż robienie tego na trasie). Mogę użyć trasy regex, aby rozwiązać mój problem (co teraz robię), ale miałem nadzieję, że będę mieć czytelną opcję.
Jesse
to niesamowite, że twórcy nie pomyśleli o użyciu nawiasów dla nazwanych opcjonalnych parametrów. ie/path/:param(/:otherOptionalParam)
r3wt

Odpowiedzi:

111

Działa to dla / path i / path / foo w express 4, zwróć uwagę na *poprzednią ?.

router.get('/path/:id*?', function(req, res, next) {
    res.render('page', { title: req.params.id });
});
Chris
źródło
43
Zauważ, że chociaż to działa, jeśli odwiedzisz /path/foo/bar/bazzle, req.params.idbędzie równe fooi req.params[0]równe /bar/bazzle, co może spowodować potknięcie niektórych osób. Roztwór czyszczący może być, aby zdefiniować ścieżkę /path/*?, która w wyrazić 4 ustawi req.params[0]się foo/bar/bazzle, co jest chyba bliżej do tego, co szukasz.
Jesse
lepiej jest kodować adres URL w swoim opcjonalnym parametrze - zezwolenie na wszystko ze ukośnikami oznacza, że ​​napotkasz konflikty w przyszłości, jeśli chcesz dodać ścieżkę taką jak app.get ('path /: required1 /: required2 /: optional? *' , handler)
Jordan,
@Jesse Jakiś sposób, aby ostatnia część była wymagana? Na przykład chcę dopasować, /path/foo/barale nie /path/foo . Próbowałem, '/path/:id/*ale *wydaje się, że pasuje również do pustego ciągu.
Franklin Yu
73

Po prostu miałem ten sam problem i rozwiązałem go. Oto, czego użyłem:

app.get('path/:required/:optional?*', ...)

To powinno działać na path/meow, path/meow/voof,path/meow/voof/moo/etc ...

Wydaje się, że porzucając /pomiędzy ?i *, ostatni /staje się również opcjonalny, podczas gdy :optional?pozostaje opcjonalny.

Andreas Hultgren
źródło
Fajne! Właśnie to przetestowałem (w wersji Express 3.0.0, nie testowałem w wersji 2.x) i działa. Jest to zdecydowanie czystsze niż mój hack RegEx.
Jesse
5
Czy wiesz, gdzie mogę przeczytać więcej na temat tych wstępnie zdefiniowanych słów kluczowych?
János
8
W
ekspresie
2
@chris odpowiedział na to pytanie za express 4 - ponieważ to ostatnia odpowiedź, przeniosłem zaakceptowaną odpowiedź na jego.
Jesse
Używając tego, napotkałem dziwny błąd, dla liczb z zerem, express go odetnie. Na przykład /: id, gdzie id = 904, req.params.id = 9 i req.params.0 = 04 (z jakiegoś powodu express zrzuca tutaj resztę). Odpowiedź Chrisa rozwiązuje ten
problem
17

Czy to zrobi to, czego szukasz?

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

Więcej o routingu Express tutaj, jeśli nie szukałeś: http://expressjs.com/guide/routing.html

Dave Ward
źródło
2
To rozwiązanie pasowałoby /path/foo/bar, ale nie /path/foo/bar/baz- *mecze splat .+, które są niezbędne do tego, co robię - zdecydowanie rtfm, wydaje się, że o tym nie wspominam, więc może nie jest to możliwe ...
Jesse
3

Oto obecny sposób, w jaki rozwiązuję ten problem, nie wydaje się, aby express obsługuje dowolną liczbę parametrów splat z opcjonalnym nazwanym parametrem:

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

Chciałbym, aby to użycie nazwano params dla czytelności i spójności - jeśli pojawi się inna odpowiedź, która na to pozwala, zaakceptuję ją.

Jesse
źródło
2

Załóżmy, że masz ten adres URL: /api/readFile/c:/a/a.txt

Jeśli chcesz req.params.pathbyć c::

'/api/readFile/:path*

Jeśli chcesz req.params.pathbyć c:/a/a.txt:

'/api/readFile/:path([^/]*)'
yaya
źródło
0

Powyższe rozwiązania wykorzystujące opcjonalne nie działają w Express 4. Próbowałem kilku sposobów używając wzorców wyszukiwania, ale też nie działały. A potem znalazłem tę metodę i wydaje się, że uruchomiono nieograniczoną ścieżkę zagnieżdżoną, 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();
});

Dopasowuje wszystko / bar, / bar / z, / bar / a / b / c itd. A potem możesz przeczytać req.originalUrl, ponieważ parametry nie są wypełnione, np. możesz spróbować porównać baseUrl i originalUrl, aby uzyskać pozostałą ścieżkę.

windmaomao
źródło
0

Omówiłem ten problem, używając kombinacji oprogramowania pośredniczącego, które dodaje końcowe ukośniki do adresu URL i router.get('/bar/*?', ..., które odbierze wszystko po /bar/i zwróci, undefinedjeśli jest tylko /bar/. Jeśli odwiedzający poprosił o to /bar, express-slashoprogramowanie pośredniczące doda ukośnik do żądania i zamieni żądanie na /bar/.

williamli
źródło