/ / ¿Cómo redireccionar las URL con una barra diagonal hacia las correspondientes sin ella? - java, spring, spring-mvc, redirect, model-view-controller

¿Cómo redirigir las URL con una barra inclinada hacia las correspondientes sin ella? - java, spring, spring-mvc, redirect, model-view-controller

Spring MVC (3.0) considera las URL con y sin barras diagonales como la misma URL.

Por ejemplo:

http://www.example.org/data/something = http://www.example.org/data/something/

Necesito redireccionar la URL con barras al final

http://www.example.org/data/something/

a la URL sin ella:

http://www.example.org/data/something

Necesito hacer esto internamente en la aplicación (así que no reescriba las reglas a través de Apache, etc.).

Una forma de hacerlo es:

@ResponseStatus(value=HttpStatus.MOVED_PERMANENTLY)
@RequestMapping(value = "/data/something/")
public String dataSomethingRedirect(...) {
return "redirect:/data/something";
}

pero esto generalmente tiene 2 problemas:

  1. demasiados controladores
  2. problema con los parámetros: como la codificación incorrecta

Pregunta

¿Hay alguna forma de interceptar todas las URL y, en caso de que tengan una barra inclinada al final, rediríjalos a la relativa sin barra diagonal?

Respuestas

13 para la respuesta № 1

Puede enumerar todas las reglas de reescritura que necesita en su configuración web

Si no hay muchos de estos, puede configurar vistas de redireccionamiento como esta

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addRedirectViewController("/my/path/", "/my/path")
.setKeepQueryParams(true)
.setStatusCode(HttpStatus.PERMANENT_REDIRECT);
}

O puedes crear una personalizada HandlerInterceptor

Pero los interceptores se producen antes de que las solicitudes se asignen a un determinado Controller.action y no tiene forma de conocer Controladores y acciones en ese contexto.

Todo lo que tienes es la API HTTPServlet y la solicitud de respuesta, para que puedas:

response.sendRedirect("http://example.org/whitout-trailing-slash");

La respuesta que no quieres leer.

Este comportamiento (URL con barra inclinada = URL sin ella) es perfectamente "válido" cuando se considera HTTP. Al menos este es el comportamiento predeterminado con Spring, que puede deshabilitar con useTrailingSlashMatch (ver javadoc)

Entonces, el uso de reglas de reescritura / redirección en el servidor de aplicaciones para el usuario podría ser una solución; pero, una vez más, no conozco sus limitaciones (¿quizás podría explicar esto y podríamos encontrar otras soluciones?).


11 para la respuesta № 2

Creo que la mejor opción sería hacer esto antes de ingresar al servlet de Spring web, usando UrlRewriteFilter. Esto asegurará que sus reglas de redirección no afecten a sus controladores.

Tenga en cuenta que escribe las reglas en su proyecto .war, no en un apache con mod_rewrite.

Ven aquí para el proyecto de la biblioteca en googlecode.

en el urlrewrite.xml escribe:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 3.1//EN" "http://www.tuckey.org/res/dtds/urlrewrite3.1.dtd">
<urlrewrite>
<rule match-type="regex">
<note>Remove trailing slash</note>
<from>^(.*)/$</from>
<to type="redirect">$1</to>
</rule>
</urlrewrite>

En el web.xml de su aplicación, agregue:

<filter>
<filter-name>UrlRewriteFilter</filter-name>
<filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
<init-param>
<param-name>confPath</param-name>
<param-value>/WEB-INF/urlrewrite.xml</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>UrlRewriteFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>

Cuidado, el orden de declaración de los filtros en el web.xml es importante, así que trata de declararlo antes de la primavera.

Por supuesto, esto es solo una fracción de lo que puede hacer UrlRewriteFilter.

Saludos.


3 para la respuesta № 3

Esto usualmente funciona para mí con URLRewriteFilter en Spring.

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 3.2//EN"
"http://www.tuckey.org/res/dtds/urlrewrite3.2.dtd">
<urlrewrite>
<rule>
<note>Remove trailing slash for SEO purposes</note>
<from>/**/</from>
<to type="permanent-redirect">%{context-path}/$1</to>
</rule>
</urlrewrite>

3 para la respuesta № 4

No estoy seguro si la primavera 3.0 tenía esto, pero la primavera 3.1 RequestMappingHandlerMapping le permite establecer una propiedad "useTrailingSlashMatch". Por defecto es cierto.

Creo que cambiarlo a falso resolvería tuproblema, sin embargo, afectaría a TODAS las asignaciones manejadas por RequestMappingHandlerMapping en su aplicación ... por lo que es posible que tenga que hacer una gran cantidad de regresión.


0 para la respuesta № 5

Estoy de acuerdo con @Brian Clozel: No creo que sea una buena idea hacer lo que quieres. Entonces, ¿por qué lo necesitas?

De todos modos, creo que la solución más sencilla es escribir un personalizado. javax.servlet.Filter. Por lo tanto, no hay dependencia de primavera. Si la URL de la solicitud termina con una barra, solo tiene que redirigir a la misma URL sin ella. Pero cuidado:

  • Todos los parámetros (GET y POST) deben agregarse como parámetros GET. ¿Estás seguro de que tu aplicación es método agnóstico?

  • Puede tener algunos problemas con la codificación. En el filtro puede codificar los parámetros POST a la codificación requerida. Pero la codificación predeterminada para los parámetros GET no está configurada en su aplicación. Se configura en server.xml (si Tomcat) y el valor predeterminado es ISO-8859-1.

¡Buena suerte!


0 para la respuesta № 6

Basado en SEO, creo que es importante hacer una distinción.

Si la URL que terminó en la barra diagonal finalExiste, está indexado en los motores de búsqueda y hay enlaces en Internet, se requiere una redirección permanente (301) como dice Uddhav Kambli. La redirección estándar (302) será mejor que tener una URL duplicada, pero no es lo suficientemente buena.

Sin embargo, si la URL nunca existió, no está indexada en Internet y no hay enlaces externos, la URL no existe. Por lo tanto, un 404, página no encontrada, es un mejor ajuste.

WEB-INF / urlrewrite.xml

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 3.1//EN"  "http://www.tuckey.org/res/dtds/urlrewrite3.1.dtd">
<urlrewrite>
<rule match-type="regex">
<note>Remove trailing slash</note>
<from>^(.+)/$</from>
<set type="status">404</set>
<to>null</to>
</rule>
</urlrewrite>

Y para completar la configuración ...

añadir a WEB-INF / web.xml

<filter>
<filter-name>UrlRewriteFilter</filter-name>
<filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
<init-param>
<param-name>confPath</param-name>
<param-value>/WEB-INF/urlrewrite.xml</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>UrlRewriteFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>

Maven

<dependency>
<groupId>org.tuckey</groupId>
<artifactId>urlrewritefilter</artifactId>
<version>4.0.3</version>
</dependency>

0 para la respuesta № 7

Descubrí que esto también se puede manejar mucho más simplemente usando un bean ErrorViewResolver en algún lugar de su @Configuration:

@Autowired
private DefaultErrorViewResolver defaultErrorViewResolver;

@Bean
ErrorViewResolver errorViewResolver() {
return new ErrorViewResolver() {
@Override
public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
if(model.containsKey("path") && !model.get("path").toString().endsWith("/")) {
return new ModelAndView("redirect:"+model.get("path") + "/");
}
return defaultErrorViewResolver.resolveErrorView(request, status, model);
}
};
}

No estoy seguro si esto es una buena o mala práctica, peroes efectivo en mi circunstancia y hace exactamente lo que necesito que haga para una ruta arbitraria "foo": responda con un redireccionamiento 302 a / foo / cuando solicite / foo y responda como debería cuando solicite / foo.