ChatGPT解决这个技术问题 Extra ChatGPT

Redirect to an external URL from controller action in Spring MVC

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,


b
buræquete

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

Its even simpler if you directly return a String rather then the ModelAndView.
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).
Can we also add cookies during redirect to External URL.
First method requires @ResponseStatus(HttpStatus.FOUND)
@Rinat Mukhamedgaliev In this ModelAndView("redirect:" + projectUrl); Statement what would be the key will be taken as default, if the added thing is value ?
m
matsev

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.


The RedirectView was the only one that seemed to work for me!
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]
k
k13i

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

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.
@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?
d
daniel.eichten

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

But in this way the redirect is a GET or does it remain a POST? How do I redirect as POST?
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.
I
Ivan Mushketyk

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

L
Lord Nighton

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

I think this method is better than RedirectView as it is working in the postman also.
s
sreeprasad

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


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.
V
Vijay Kukkala

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


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.
N
Neptune

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()
    }
}

h
hd1

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


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.