Redirect to an external URL from controller action in Spring MVC
Asked Answered
C

10

182

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,

Cloutman answered 30/7, 2013 at 19:32 Comment(0)
J
278

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);
}
Juba answered 31/7, 2013 at 3:57 Comment(7)
Its even simpler if you directly return a String rather then the ModelAndView.Titian
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).Liberalize
Can we also add cookies during redirect to External URL.Ostracod
First method requires @ResponseStatus(HttpStatus.FOUND)Cusick
@Rinat Mukhamedgaliev In this ModelAndView("redirect:" + projectUrl); Statement what would be the key will be taken as default, if the added thing is value ?Courland
The first way is the best, since it does not require Spring MVC.Judge
@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?Sterol
E
89

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.

Elyssa answered 16/10, 2014 at 21:11 Comment(2)
The RedirectView was the only one that seemed to work for me!Hockey
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]Velvavelvet
I
66

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();
  }
Immature answered 28/3, 2019 at 17:0 Comment(2)
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.Pasteur
@Immature 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?Sterol
T
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;
}
Titian answered 1/8, 2013 at 11:57 Comment(2)
But in this way the redirect is a GET or does it remain a POST? How do I redirect as POST?Licorice
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.Titian
L
37

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");
}
Liberalize answered 1/10, 2015 at 21:41 Comment(0)
M
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);
}
Marinmarina answered 30/5, 2015 at 8:19 Comment(1)
I think this method is better than RedirectView as it is working in the postman also.Shooter
S
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

Savarin answered 30/7, 2013 at 20:38 Comment(1)
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.Cleveite
D
3

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

Diffluent answered 30/7, 2013 at 20:54 Comment(1)
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.Chancery
S
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()
    }
}
Sweetandsour answered 21/1, 2022 at 5:48 Comment(0)
L
-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

Lockyer answered 27/5, 2017 at 6:20 Comment(1)
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.Autorotation

© 2022 - 2024 — McMap. All rights reserved.