156

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
  • 24,303
  • 27
  • 100
  • 159

10 Answers10

254

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
  • 13,529
  • 4
  • 40
  • 81
Rinat Mukhamedgaliev
  • 5,079
  • 8
  • 40
  • 58
74

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
  • 29,504
  • 14
  • 112
  • 148
  • 2
    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
52

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,456
  • 19
  • 25
  • 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
52

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
  • 3,471
  • 3
  • 30
  • 58
33

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
  • 7,469
  • 6
  • 43
  • 63
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,630
  • 20
  • 15
8

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,134
  • 3
  • 24
  • 32
  • 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
  • 32,598
  • 5
  • 75
  • 87
  • 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