Redirigir a una URL externa desde la acción del controlador en Spring MVC

118

He notado que el siguiente código redirige al usuario a una URL dentro del proyecto,

@RequestMapping(method = RequestMethod.POST)
public String processForm(HttpServletRequest request, LoginForm loginForm, 
                          BindingResult result, ModelMap model) 
{
    String redirectUrl = "yahoo.com";
    return "redirect:" + redirectUrl;
}

mientras que lo siguiente redirige correctamente según lo previsto, pero requiere http: // o https: //

@RequestMapping(method = RequestMethod.POST)
    public String processForm(HttpServletRequest request, LoginForm loginForm, 
                              BindingResult result, ModelMap model) 
    {
        String redirectUrl = "http://www.yahoo.com";
        return "redirect:" + redirectUrl;
    }

Quiero que la redirección siempre redirija a la URL especificada, ya sea que tenga un protocolo válido o no y no quiero redirigir a una vista. ¿Cómo puedo hacer eso?

Gracias,

Jake
fuente

Respuestas:

208

Puedes hacerlo de dos formas.

Primero:

@RequestMapping(value = "/redirect", method = RequestMethod.GET)
public void method(HttpServletResponse httpServletResponse) {
    httpServletResponse.setHeader("Location", projectUrl);
    httpServletResponse.setStatus(302);
}

Segundo:

@RequestMapping(value = "/redirect", method = RequestMethod.GET)
public ModelAndView method() {
    return new ModelAndView("redirect:" + projectUrl);
}
Rinat Mukhamedgaliev
fuente
19
Es aún más simple si devuelve directamente un String en lugar de ModelAndView.
daniel.eichten
24
Parece que en el primer método debe establecer el código de retorno en 302. De lo contrario, un servidor devolvería una respuesta con el código 200 y el encabezado de ubicación que no causa redireccionamiento en mi caso (Firefox 41.0).
Ivan Mushketyk
¿Podemos también agregar cookies durante la redirección a una URL externa?
Srikar
1
Requiere primer método@ResponseStatus(HttpStatus.FOUND)
lapkritinis
@Rinat Mukhamedgaliev En este ModelAndView ("redireccionamiento:" + projectUrl); Enunciado ¿cuál sería la clave que se tomará por defecto, si el valor añadido es?
JAVA
56

Puede utilizar el RedirectView. Copiado de JavaDoc :

Vista que redirecciona a una URL relativa absoluta, relativa al contexto o relativa a la solicitud actual

Ejemplo:

@RequestMapping("/to-be-redirected")
public RedirectView localRedirect() {
    RedirectView redirectView = new RedirectView();
    redirectView.setUrl("http://www.yahoo.com");
    return redirectView;
}

También puede utilizar ResponseEntity, por ejemplo,

@RequestMapping("/to-be-redirected")
public ResponseEntity<Object> redirectToExternalUrl() throws URISyntaxException {
    URI yahoo = new URI("http://www.yahoo.com");
    HttpHeaders httpHeaders = new HttpHeaders();
    httpHeaders.setLocation(yahoo);
    return new ResponseEntity<>(httpHeaders, HttpStatus.SEE_OTHER);
}

Y por supuesto, vuelve redirect:http://www.yahoo.comcomo han mencionado otros.

matsev
fuente
¡RedirectView fue el único que pareció funcionar para mí!
James111
Estoy teniendo un comportamiento extraño con Redirect View, en el sitio web obtengo: [código] [27/04/17 13: 45: 55: 385 CDT] 00001303 webapp E com.ibm.ws.webcontainer.webapp.WebApp logServletError SRVE0293E : [Error de servlet] - [DispatcherPrincipal]: java.io.IOException: patrón no permitido en mx.isban.security.components.SecOutputFilter $ WrapperRsSecured.sendRedirect (SecOutputFilter.java:234) en javax.servlet.httServletp.Restt. sendRedirect (HttpServletResponseWrapper.java:145) [código]
Carlos de Luna Saenz
49

Al analizar la implementación real de UrlBasedViewResolver y RedirectView, la redirección siempre será contextRelative si su objetivo de redirección comienza con /. Por lo tanto, también enviar un //yahoo.com/path/to/resource no ayudaría a obtener una redirección relativa del protocolo.

Entonces, para lograr lo que está intentando, podría hacer algo como:

@RequestMapping(method = RequestMethod.POST)
public String processForm(HttpServletRequest request, LoginForm loginForm, 
                          BindingResult result, ModelMap model) 
{
    String redirectUrl = request.getScheme() + "://www.yahoo.com";
    return "redirect:" + redirectUrl;
}
daniel.eichten
fuente
¿Pero de esta manera la redirección es un GET o sigue siendo un POST? ¿Cómo redirecciono como POST?
Accollativo
Bueno, en realidad, por defecto, esto devuelve un 302, lo que significa que debería emitir un GET contra la URL proporcionada. Para que la redirección mantenga el mismo método, también debe establecer un código diferente (307 a partir de HTTP / 1.1). Pero estoy bastante seguro de que los navegadores bloquearán esto si va en contra de una dirección absoluta usando una combinación de puerto / host diferente debido a problemas de seguridad.
daniel.eichten
26

Otra forma de hacerlo es simplemente usar el sendRedirectmétodo:

@RequestMapping(
    value = "/",
    method = RequestMethod.GET)
public void redirectToTwitter(HttpServletResponse httpServletResponse) throws IOException {
    httpServletResponse.sendRedirect("https://twitter.com");
}
Ivan Mushketyk
fuente
22

Puede hacer esto de una manera bastante concisa usando ResponseEntityasí:

  @GetMapping
  ResponseEntity<Void> redirect() {
    return ResponseEntity.status(HttpStatus.FOUND)
        .location(URI.create("http://www.yahoo.com"))
        .build();
  }
k13i
fuente
1
Esta debería ser la respuesta aceptada. Extremadamente fácil de configurar y utilizar.
cyberbit
9

Para mi funciona bien:

@RequestMapping (value = "/{id}", method = RequestMethod.GET)
public ResponseEntity<Object> redirectToExternalUrl() throws URISyntaxException {
    URI uri = new URI("http://www.google.com");
    HttpHeaders httpHeaders = new HttpHeaders();
    httpHeaders.setLocation(uri);
    return new ResponseEntity<>(httpHeaders, HttpStatus.SEE_OTHER);
}
Lord Nighton
fuente
Creo que este método es mejor que RedirectView, ya que también funciona en el cartero.
mehdi mohammadi
8

Para la URL externa, debe utilizar " http://www.yahoo.com " como URL de redireccionamiento.

Esto se explica en la redirección: prefijo de la documentación de referencia de Spring.

redireccionar: / myapp / some / resource

redirigirá en relación con el contexto de Servlet actual, mientras que un nombre como

redireccionamiento: http://myhost.com/some/arbitrary/path

redirigirá a una URL absoluta

sreeprasad
fuente
3

¿Probó RedirectView donde puede proporcionar el parámetro contextRelative?

Vijay Kukkala
fuente
Ese parámetro es útil para las rutas que comienzan (o no) con /para verificar si debería ser relativo al contexto de la aplicación web. La solicitud de redireccionamiento seguirá siendo para el mismo host.
Sotirios Delimanolis
-2

En resumen "redirect://yahoo.com"te lo prestará yahoo.com.

donde como "redirect:yahoo.com"te prestará es your-context/yahoo.comdecir, por ejemplolocalhost:8080/yahoo.com

hd1
fuente
Ambas soluciones tienen el mismo comando: "En resumen" redireccionar: yahoo.com "vs" donde como "redireccionar: yahoo.com", y solo funciona la redirección de URL relativa.
partizanos