176

I have noticed the following code is redirecting the User to a URL inside the project,

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

whereas, the following is redirecting properly as intended, but requires http:// or 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;
    }

I want the redirect to always redirect to the URL specified, whether it has a valid protocol in it or not and do not want to redirect to a view. How can I do that?

Thanks,

Jake
  • 25,479
  • 31
  • 107
  • 168

10 Answers10

273

You can do it with two ways.

First:

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

Second:

@RequestMapping(value = "/redirect", method = RequestMethod.GET)
public ModelAndView method() {
    return new ModelAndView("redirect:" + projectUrl);
}
buræquete
  • 14,226
  • 4
  • 44
  • 89
Rinat Mukhamedgaliev
  • 5,401
  • 8
  • 41
  • 59
  • 23
    Its even simpler if you directly return a String rather then the ModelAndView. – daniel.eichten Sep 05 '15 at 08:57
  • 29
    It seems that in the first method you should set return code to 302. Otherwise a server would return a response with code 200 and Location header which does not cause redirect in my case (Firefox 41.0). – Ivan Mushketyk Oct 01 '15 at 21:44
  • Can we also add cookies during redirect to External URL. – Srikar Mar 09 '18 at 00:27
  • 1
    First method requires `@ResponseStatus(HttpStatus.FOUND)` – lapkritinis May 09 '18 at 12:37
  • @Rinat Mukhamedgaliev In this ModelAndView("redirect:" + projectUrl); Statement what would be the key will be taken as default, if the added thing is value ? – JAVA Sep 14 '18 at 12:14
  • The first way is the best, since it does not require Spring MVC. – Holger Ludvigsen Feb 05 '21 at 09:22
  • @Rinat Mukhamedgaliev, one question please. In the code above, is it possible to replace the object `projectUrl` with multiple URL's that come from Thymeleaf? Any ideas on how to implement this? – Alex_Pap Jul 15 '22 at 20:09
85

You can use the RedirectView. Copied from the JavaDoc:

View that redirects to an absolute, context relative, or current request relative URL

Example:

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

You can also use a ResponseEntity, e.g.

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

And of course, return redirect:http://www.yahoo.com as mentioned by others.

matsev
  • 32,104
  • 16
  • 121
  • 156
  • 3
    The RedirectView was the only one that seemed to work for me! – James111 Jul 29 '16 at 01:13
  • I am having a stange behavour wiwth Redirect View, on webshpere i am getting: [code][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: pattern not allowed at mx.isban.security.components.SecOutputFilter$WrapperRsSecured.sendRedirect(SecOutputFilter.java:234) at javax.servlet.http.HttpServletResponseWrapper.sendRedirect(HttpServletResponseWrapper.java:145)[code] – Carlos de Luna Saenz Apr 27 '17 at 18:55
64

You can do this in pretty concise way using ResponseEntity like this:

  @GetMapping
  ResponseEntity<Void> redirect() {
    return ResponseEntity.status(HttpStatus.FOUND)
        .location(URI.create("http://www.yahoo.com"))
        .build();
  }
k13i
  • 4,011
  • 3
  • 35
  • 63
  • 1
    This answer is perfect because it allows redirects and also you can choose to not redirect and just return something in the body. It's very flexibel. – Martijn Hiemstra Jan 21 '22 at 10:59
  • @k13i I have the same problem in my app, in which I need to pass a list of URL's stored in DB back to the controller for redirection purposes. How can I replace the `URI.create("http://www.yahoo.com")` with values handled from Thymeleaf? – Alex_Pap Jul 15 '22 at 20:14
54

Looking into the actual implementation of UrlBasedViewResolver and RedirectView the redirect will always be contextRelative if your redirect target starts with /. So also sending a //yahoo.com/path/to/resource wouldn't help to get a protocol relative redirect.

So to achieve what you are trying you could do something like:

@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
  • 2,535
  • 19
  • 26
  • 1
    But in this way the redirect is a GET or does it remain a POST? How do I redirect as POST? – Accollativo Apr 01 '16 at 09:01
  • Well actually per default this is returning a 302 which means it should issue a GET against the provided url. For redirection keeping the same method you should also set a different code (307 as of HTTP/1.1). But I'm pretty sure that browsers will block this if it is going against an absolute address using a different host/port-combination due to security issues. – daniel.eichten Apr 01 '16 at 09:30
36

Another way to do it is just to use the sendRedirect method:

@RequestMapping(
    value = "/",
    method = RequestMethod.GET)
public void redirectToTwitter(HttpServletResponse httpServletResponse) throws IOException {
    httpServletResponse.sendRedirect("https://twitter.com");
}
Ivan Mushketyk
  • 8,107
  • 7
  • 50
  • 67
10

For me works fine:

@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
  • 1,670
  • 21
  • 15
9

For external url you have to use "http://www.yahoo.com" as the redirect url.

This is explained in the redirect: prefix of Spring reference documentation.

redirect:/myapp/some/resource

will redirect relative to the current Servlet context, while a name such as

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

will redirect to an absolute URL

sreeprasad
  • 3,242
  • 3
  • 27
  • 33
  • This is the most accurate answer imo. The op was asking to redirect the URL as an absolute URL even it has no scheme in it. The answer is: no you can't, you have to specify the scheme. All the rest answers I see work because they use `http://www.yahoo.com`, `http://www.google.com`, etc. as an example input of their solution. If they use `www.yahoo.com`, no matter `ResponseEntity` or `redirect:`, it will break. Tried with Spring boot 2.5.2 and Chrome, Firefox and Safari. – fishstick Jul 11 '21 at 18:00
3

Did you try RedirectView where you can provide the contextRelative parameter?

Vijay Kukkala
  • 362
  • 5
  • 14
  • That parameter is useful for paths that start (or don't) with `/` to check if it should be relative to the webapp context. The redirect request will still be for the same host. – Sotirios Delimanolis Jul 30 '13 at 21:03
0

This works for me, and solved "Response to preflight request doesn't pass access control check ..." issue.

Controller

    RedirectView doRedirect(HttpServletRequest request){

        String orgUrl = request.getRequestURL()
        String redirectUrl = orgUrl.replaceAll(".*/test/","http://xxxx.com/test/")

        RedirectView redirectView = new RedirectView()
        redirectView.setUrl(redirectUrl)
        redirectView.setStatusCode(HttpStatus.TEMPORARY_REDIRECT)
        return redirectView
    }

and enable securty

@EnableWebSecurity
class SecurityConfigurer extends WebSecurityConfigurerAdapter{
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable()
    }
}
Neptune
  • 1
  • 1
-1

In short "redirect://yahoo.com" will lend you to yahoo.com.

where as "redirect:yahoo.com" will lend you your-context/yahoo.com ie for ex- localhost:8080/yahoo.com

hd1
  • 33,938
  • 5
  • 80
  • 91
  • both solutions have the same command : "In short "redirect:yahoo.com" vs "where as "redirect:yahoo.com", and only the relative url redirection is working. – partizanos Feb 09 '18 at 16:21