Express.js Routing: optionaler Splat-Parameter?

80

Ich habe eine Route, die so aussieht:

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

Dies funktioniert jedoch nicht - wenn ich anrufe path/foo/bar, trifft es die Route, aber wenn ich anrufe path/foo, funktioniert es nicht.

Ist es möglich, einen optionalen Splat-Parameter zu haben, oder muss ich einen regulären Ausdruck verwenden, um dies zu erkennen?

Bearbeiten :

Um es klarer zu machen, hier sind die Anforderungen, die ich zu erreichen versuche:

  • Der erste und der zweite Parameter sind erforderlich
  • Der erste Parameter ist statisch, der zweite ist ein benannter Parameter.
  • Eine beliebige Anzahl optionaler zusätzlicher Parameter kann angehängt werden und trotzdem die Route treffen.
Jesse
quelle
1
Was versuchst du zu machen? Wenn Sie Splat nicht kennen müssen, tun Sie es einfach '/path/:firstParam/*'. Wenn Sie es brauchen, tun Sie es '/path/:firstParam/:secondParam?/*'.
Jonathan Ong
1
Ich möchte, dass der Splat optional ist - das erste Beispiel, das Sie angegeben haben, würde nicht übereinstimmen /path/foo(so sah meine Route ursprünglich aus, bevor ich einen optionalen Splat wollte). Darüber hinaus negiert in Ihrem zweiten Beispiel das Hinzufügen des Splat den optionalen zweiten Parameter - stimmt /path/foonicht mit Ihrem zweiten Muster überein (und auch nicht /path/foo/bar...) - einer der nervigeren Teile des Express-Routers.
Jesse
1
persönlich würde ich mich einfach für /path/:firstParamund /path/:firstParam/:secondParam/als zwei separate Router mit einem gemeinsam genutzten Controller entscheiden. Keine Notwendigkeit, Ihre URLs verwirrend zu machen
Jonathan Ong
Mit nEndpunkten ist für das Design der App notwendig - ich bin nicht nur das Routing zu 1-3 params kann eine beliebige Zahl sein, so eine Begrenzung der Anzahl der params aufweisen , ist keine Option (sicher, ich 10 Endpunkte erstellen könnte, Aber wenn Express diese Arbeit macht, ist das nicht besser als auf einer Route. Ich kann eine Regex-Route verwenden, um mein Problem zu lösen (was ich gerade mache), aber ich hatte gehofft, eine lesbare Option zu haben.
Jesse
Es ist erstaunlich, dass die Entwickler nicht daran gedacht haben, einfach Klammern für benannte optionale Parameter zu verwenden. dh/path/:param(/:otherOptionalParam)
r3wt

Antworten:

110

Dies funktioniert für / path und / path / foo in Express 4, beachten Sie die *vorherigen ?.

router.get('/path/:id*?', function(req, res, next) {
    res.render('page', { title: req.params.id });
});
Chris
quelle
42
Beachten Sie, dass während dies funktioniert, wenn Sie besuchen /path/foo/bar/bazzle, req.params.idgleich foound req.params[0]gleich ist /bar/bazzle, was einige Leute stolpern kann. Eine sauberere Lösung kann sein , den Pfad zu definieren , wie /path/*?, die ausdrücken 4 gesetzt req.params[0]zu foo/bar/bazzle, was wahrscheinlich näher ist , was Sie suchen.
Jesse
Sie sind besser dran, Ihren optionalen Parameter per URL zu codieren. Wenn Sie alles mit Schrägstrichen zulassen, treten später Konflikte auf, wenn Sie einen Pfad wie app.get hinzufügen möchten ('path /: required1 /: required2 /: optional? *'). , Handler)
Jordanien
@ Jesse Gibt es eine Möglichkeit, den letzten erforderlichen Teil zu erstellen? Zum Beispiel möchte ich /path/foo/baraber nicht übereinstimmen /path/foo. Ich habe es versucht, '/path/:id/*aber es *scheint auch mit einer leeren Zeichenfolge übereinzustimmen.
Franklin Yu
72

Ich hatte gerade das gleiche Problem und löste es. Das habe ich benutzt:

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

Dies sollte für Arbeit path/meow, path/meow/voof, path/meow/voof/moo/etc...

Es scheint, als würde durch das Löschen von /zwischen ?und *das letzte ebenfalls /optional, während es :optional?optional bleibt.

Andreas Hultgren
quelle
Cool! Ich habe dies gerade getestet (in Express 3.0.0, nicht in 2.x getestet) und es funktioniert. Dies ist definitiv sauberer als mein RegEx-Hack.
Jesse
5
Wissen Sie, wo ich mehr über diese vordefinierten Schlüsselwörter lesen kann?
János
8
In Express 4.0x scheint dies nicht mehr zu funktionieren
Reveroveroverflow
2
@chris hat dies für Express 4 beantwortet - da dies die neueste ist, habe ich die akzeptierte Antwort auf seine verschoben.
Jesse
Bei der Verwendung von Zahlen mit Null ist ein seltsamer Fehler aufgetreten. Express schneidet ihn ab. Zum Beispiel /: id mit id = 904, req.params.id = 9 und req.params.0 = 04 (Express-Dumps für diesen Rest hier aus irgendeinem Grund). Chris Antwort behebt dieses
Problem
17

Wird das tun, wonach Sie suchen?

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

Weitere Informationen zum Routing von Express finden Sie hier, wenn Sie nicht nachgesehen haben: http://expressjs.com/guide/routing.html

Dave Ward
quelle
2
Diese Lösung würde passen /path/foo/bar, aber nicht /path/foo/bar/baz- die *Splat-Matches .+, die für das, was ich tue, notwendig sind - ich habe definitiv rtfm, scheint es nicht zu erwähnen, also ist es vielleicht nicht möglich ...
Jesse
3

Hier ist die aktuelle Art und Weise, wie ich dieses Problem löse. Es scheint nicht, dass Express eine beliebige Anzahl von Splat-Parametern mit einem optionalen benannten Parameter unterstützt:

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

Ich würde diese Verwendung gerne als Parameter für Lesbarkeit und Konsistenz verwenden lassen - wenn eine andere Antwort auftaucht, die dies zulässt, werde ich sie akzeptieren.

Jesse
quelle
2

Angenommen, Sie haben diese URL: /api/readFile/c:/a/a.txt

Wenn Sie möchten , req.params.pathsein c::

'/api/readFile/:path*

Wenn Sie möchten , req.params.pathsein c:/a/a.txt:

'/api/readFile/:path([^/]*)'
yaya
quelle
0

Die oben genannten Lösungen mit optional funktionieren in Express 4 nicht. Ich habe verschiedene Methoden zur Verwendung von Suchmustern ausprobiert, aber auch nicht. Und dann habe ich diese Methode gefunden und scheint für den unbegrenzten verschachtelten Pfad http://expressjs.com/api.html#router gefeuert zu sein

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

Es stimmt mit allen überein / bar, / bar / z, / bar / a / b / c usw. Und danach können Sie req.originalUrl lesen, da die Parameter nicht gefüllt sind, z. Sie können versuchen, baseUrl und originalUrl zu vergleichen, um den verbleibenden Pfad zu erhalten.

Windmaomao
quelle
0

Ich habe um dieses Problem durch eine Kombination aus einer Middleware , die folgenden Schrägstriche zu URL hinzufügen und router.get('/bar/*?', ..., die alles abholen wird nach /bar/und Rückkehr , undefinedwenn es gerade ist /bar/. Wenn der Besucher danach fragt /bar, express-slashfügt die Middleware der Anfrage einen Schrägstrich hinzu und wandelt die Anfrage in um /bar/.

williamli
quelle