Enrutamiento Express.js: ¿param splat opcional?


82

Tengo una ruta que se parece a esto:

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

sin embargo, esto no funciona - si llamo path/foo/bar, llega a la ruta, pero si llamo path/foo, no funciona.

¿Es posible tener un parámetro de splat opcional o tengo que usar una expresión regular para detectar esto?

Editar :

para ser más claro, estos son los requisitos que estoy tratando de lograr:

  • el primer y segundo parámetro son obligatorios
  • el primer parámetro es estático, el segundo es un parámetro con nombre.
  • se puede agregar cualquier número de parámetros adicionales opcionales y aún así llegar a la ruta.

1
¿que estás tratando de hacer? si no necesita saber splat, simplemente hágalo '/path/:firstParam/*'. Si lo necesita, hágalo '/path/:firstParam/:secondParam?/*'.
Jonathan Ong

1
Estoy buscando que el símbolo sea opcional; el primer ejemplo que dio no coincidiría /path/foo(así es como se veía originalmente mi ruta antes de que quisiera un símbolo opcional). Además, en su segundo ejemplo, agregar el símbolo en realidad niega el segundo parámetro opcional /path/foo, no coincidirá con su segundo patrón (ni tampoco lo hará /path/foo/bar...), una de las partes más molestas del enrutador express '.
Jesse

1
personalmente, optaría por /path/:firstParamy /path/:firstParam/:secondParam/como dos enrutadores separados con un controlador compartido. no hay necesidad de hacer que sus URL sean confusas
Jonathan Ong

Tener npuntos finales es necesario para el diseño de la aplicación; no solo estoy enrutando a 1-3 parámetros, puede ser cualquier número, por lo que tener un límite en el número de parámetros no es una opción (claro, podría crear 10 puntos finales pero que express haga ese trabajo no es mejor que hacerlo en una ruta). Puedo usar una ruta de expresiones regulares para resolver mi problema (lo que estoy haciendo ahora), pero esperaba tener una opción legible.
Jesse

es sorprendente que los desarrolladores no pensaran en usar simplemente paréntesis para parámetros opcionales con nombre. ie/path/:param(/:otherOptionalParam)
r3wt

Respuestas:


111

Esto funciona para / path y / path / foo en express 4, tenga en cuenta lo *anterior ?.

router.get('/path/:id*?', function(req, res, next) {
    res.render('page', { title: req.params.id });
});

43
Tenga en cuenta que si bien esto funciona, si visita /path/foo/bar/bazzle, req.params.idserá igual fooy req.params[0]será igual /bar/bazzle, lo que puede hacer tropezar a algunas personas. Una solución más limpia puede ser definir la ruta como /path/*?, que en express 4 se establecerá req.params[0]en foo/bar/bazzle, que probablemente esté más cerca de lo que está buscando.
Jesse

es mejor que codifique la URL de su parámetro opcional: permitir cualquier cosa con barras significa que se encontrará con conflictos en el futuro si desea agregar una ruta como app.get ('ruta /: requerido1 /: requerido2 /: opcional? *' , manejador)
Jordania

@Jesse ¿Alguna forma de hacer la última parte requerida? Por ejemplo, quiero coincidir /path/foo/barpero no /path/foo . Lo intenté, '/path/:id/*pero *parece coincidir con una cadena vacía también.
Franklin Yu

73

Simplemente tuve el mismo problema y lo resolví. Esto es lo que usé:

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

Esto debería funcionar para path/meow, path/meow/voof, path/meow/voof/moo/etc...

Parece que al eliminar el /entre ?y *, el último también se /vuelve opcional, mientras que :optional?sigue siendo opcional.


¡Frio! Acabo de probar esto (en express 3.0.0, no lo he probado en 2.x) y funciona. Esto es definitivamente más limpio que mi truco de RegEx.
Jesse

5
¿Sabe dónde puedo leer más sobre estas palabras clave predefinidas?
János

8
En express 4.0x, esto parece no funcionar más
regretoverflow

2
@chris respondió esto para Express 4, ya que es el último, moví la respuesta aceptada a la suya.
Jesse

Me encontré con un error extraño al usar esto, para los números con cero, Express lo cortará. Por ejemplo /: id donde id = 904, req.params.id = 9 y req.params.0 = 04 (express vuelca este resto aquí por alguna razón). La respuesta de Chris corrige esto
emiidee

17

¿Hará esto lo que buscas?

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

Más sobre el enrutamiento Express aquí, si no ha mirado: http://expressjs.com/guide/routing.html


2
Esta solución coincidiría /path/foo/bar, pero no /path/foo/bar/baz- el *splat coincide .+, que es necesario para lo que estoy haciendo - definitivamente tengo rtfm, no parece mencionarlo, así que tal vez no sea posible ...
Jesse

3

Esta es la forma actual en que estoy resolviendo este problema, no parece que express admita ningún número de parámetros de splat con un parámetro opcional llamado:

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

Me encantaría tener este uso llamado params por legibilidad y consistencia; si aparece otra respuesta que lo permita, la aceptaré.


2

Suponga que tiene esta URL: /api/readFile/c:/a/a.txt

Si quieres req.params.pathser c::

'/api/readFile/:path*

Si quieres req.params.pathser c:/a/a.txt:

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

0

Las soluciones anteriores que usan opcional no funcionan en Express 4. Y probé un par de formas usando patrones de búsqueda, pero tampoco funcionó. Y luego encontré este método y parece disparado por una ruta anidada ilimitada, 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();
});

Coincide con todos / bar, / bar / z, / bar / a / b / c, etc. Y después de eso, puede leer req.originalUrl, ya que los parámetros no están llenos, ej. puede intentar comparar baseUrl y originalUrl para obtener la ruta restante.


0

Solucioné este problema usando una combinación de middleware que agrega barras inclinadas a la URL y router.get('/bar/*?', ..., que recogerá todo después /bar/, y regresará undefinedsi es solo /bar/. Si el visitante lo solicitó /bar, el express-slashmiddleware agregará una barra a la solicitud y la convertirá en /bar/.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.