Redirecionar para um URL externo da ação do controlador no Spring MVC

118

Percebi que o código a seguir está redirecionando o usuário para uma URL dentro do projeto,

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

enquanto o seguinte está redirecionando corretamente como pretendido, mas requer http: // ou 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;
    }

Quero que o redirecionamento sempre redirecione para a URL especificada, quer tenha um protocolo válido ou não, e não quero redirecionar para uma exibição. Como eu posso fazer isso?

Obrigado,

Jake
fonte

Respostas:

208

Você pode fazer isso de duas maneiras.

Primeiro:

@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
fonte
19
É ainda mais simples se você retornar diretamente uma String em vez de ModelAndView.
daniel.eichten
24
Parece que no primeiro método você deve definir o código de retorno para 302. Caso contrário, um servidor retornaria uma resposta com o código 200 e o cabeçalho Location que não causa redirecionamento no meu caso (Firefox 41.0).
Ivan Mushketyk,
Também podemos adicionar cookies durante o redirecionamento para URL externo.
Srikar,
1
O primeiro método requer@ResponseStatus(HttpStatus.FOUND)
lapkritinis
@Rinat Mukhamedgaliev Neste ModelAndView ("redirect:" + projectUrl); Instrução qual seria a chave será tomada como default, se o que agregou for valor?
JAVA
56

Você pode usar o RedirectView. Copiado do JavaDoc :

Visualização que redireciona para um URL absoluto, relativo ao contexto ou relativo à solicitação atual

Exemplo:

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

Você também pode usar um ResponseEntity, por exemplo

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

E, claro, volte redirect:http://www.yahoo.comconforme mencionado por outros.

Matsev
fonte
O RedirectView foi o único que pareceu funcionar para mim!
James111
Estou tendo um comportamento estranho com a visualização de redirecionamento, no webshpere estou recebendo: [código] [27/04/17 13: 45: 55: 385 CDT] 00001303 webapp E com.ibm.ws.webcontainer.webapp.WebApp logServletError SRVE0293E : [Erro de servlet] - [DispatcherPrincipal]: java.io.IOException: padrão não permitido em mx.isban.security.components.SecOutputFilter $ WrapperRsSecured.sendRedirect (SecOutputFilter.java:234) em javax.servlet.http.HttpSrapervletResponlet. sendRedirect (HttpServletResponseWrapper.java:145) [código]
Carlos de Luna Saenz
49

Olhando para a implementação real de UrlBasedViewResolver e RedirectView, o redirecionamento sempre será contextRelative se seu destino de redirecionamento começar com /. Portanto, o envio de //yahoo.com/path/to/resource não ajudaria a obter um redirecionamento relativo de protocolo.

Então, para alcançar o que você está tentando, você pode fazer 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
fonte
Mas, desta forma, o redirecionamento é um GET ou permanece um POST? Como faço para redirecionar como POST?
Accollativo
Bem, na verdade, por padrão, isso está retornando um 302, o que significa que deve emitir um GET contra o url fornecido. Para o redirecionamento mantendo o mesmo método, você também deve definir um código diferente (307 a partir de HTTP / 1.1). Mas tenho quase certeza de que os navegadores irão bloquear isso se for contra um endereço absoluto usando uma combinação diferente de host / porta devido a problemas de segurança.
daniel.eichten
26

Outra maneira de fazer isso é usar o sendRedirectmétodo:

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

Você pode fazer isso de forma bastante concisa usando ResponseEntityassim:

  @GetMapping
  ResponseEntity<Void> redirect() {
    return ResponseEntity.status(HttpStatus.FOUND)
        .location(URI.create("http://www.yahoo.com"))
        .build();
  }
k13i
fonte
1
Esta deve ser a resposta aceita. Extremamente fácil de configurar e usar.
cyberbit
9

Para mim funciona bem:

@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
fonte
Acho que esse método é melhor que o RedirectView, pois funciona no carteiro também.
mehdi mohammadi
8

Para url externo, você deve usar " http://www.yahoo.com " como o url de redirecionamento.

Isso é explicado no redirect: prefixo da documentação de referência do Spring.

redirect: / myapp / some / resource

irá redirecionar em relação ao contexto do Servlet atual, enquanto um nome como

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

irá redirecionar para um URL absoluto

sreeprasad
fonte
3

Você tentou RedirectView, onde pode fornecer o parâmetro contextRelative?

Vijay Kukkala
fonte
Esse parâmetro é útil para caminhos que começam (ou não) com /para verificar se ele deve ser relativo ao contexto do webapp. A solicitação de redirecionamento ainda será para o mesmo host.
Sotirios Delimanolis
-2

Em suma, "redirect://yahoo.com"vou emprestar para você yahoo.com.

onde "redirect:yahoo.com"vai lhe emprestar, your-context/yahoo.comou seja, para ex-localhost:8080/yahoo.com

hd1
fonte
ambas as soluções têm o mesmo comando: "Resumindo" redirect: yahoo.com "vs" onde como "redirect: yahoo.com", e apenas o redirecionamento de url relativo está funcionando.
partizanos