Spring MVC "redirect:" prefix always redirects to http -- how do I make it stay on https?

SpringSpring Mvc

Spring Problem Overview


I solved this myself, but I spent so long discovering such a simple solution, I figured it deserved to be documented here.

I have a typical Spring 3 MVC setup with an InternalResourceViewResolver:

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
  <property name="prefix" value="/" />
  <property name="suffix" value=".jsp" />
</bean>

I have a pretty simple handler method in my controller, but I've simplified it even more for this example:

@RequestMapping("/groups")
public String selectGroup() {
    return "redirect:/";
}

The problem is, if I browse to https://my.domain.com/groups, I end up at http://my.domain.com/ after the redirect. (In actuality my load-balancer redirects all http requests to https, but this just causes multiple browser alerts of the type "You are leaving/entering a secure connection" for folks who have such alerts turned on.)

So the question is: how does one get spring to redirect to https when that's what the original request used?

Spring Solutions


Solution 1 - Spring

The short answer is, set the InternalResourceViewResolver's redirectHttp10Compatible property to false:

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
  <property name="prefix" value="/" />
  <property name="suffix" value=".jsp" />
  <property name="redirectHttp10Compatible" value="false" />
</bean>

You could do this on a per-request basis instead, by having your handler method return View instead of String, and creating the RedirectView yourself, and calling setHttp10Compatible(false).

(It turns out the culprit is HttpServletResponse.sendRedirect, which the RedirectView uses for HTTP 1.0 compatible redirects, but not otherwise. I guess this means it's dependent on your servlet container's implementation (?); I observed the problem in both Tomcat and Jetty.)

Solution 2 - Spring

Spring Boot provides this nice configuration based solution to this if you're running behind a proxy server, simply add these two properties to your application.properties file:

server.tomcat.remote_ip_header=x-forwarded-for
server.tomcat.protocol_header=x-forwarded-proto

This works for me deploying the otherwise unchanged spring-boot-sample-web-ui to Elastic Beanstalk behind an https load balancer. Without these properties the redirect on line 68 of the MessageController defaults to http and hangs.

Hope this helps.

Solution 3 - Spring

What worked for me is adding this to application.properties server.tomcat.use-relative-redirects=true

So when you have:

public function redirect() {
  return "redirect:/"
}

Without the server.tomcat.use-relative-redirects it will add a Location header like: http://my-host.com/. With the server.tomcat.use-relative-redirects it will look like: /. So it will be relative to the current page from browser perspective.

Solution 4 - Spring

Are you sure?

Looking at the code it seems there is no difference. Both variants use the encoded url, see the sendRedirect method in RedirectView:

String encodedURL = isRemoteHost(targetUrl) ? targetUrl : response.encodeRedirectURL(targetUrl);
if (http10Compatible) {
    // Other if/else stuff depending on status code
    
    // Send status code 302 by default.
    response.sendRedirect(encodedURL);
}
else {
    HttpStatus statusCode = getHttp11StatusCode(request, response, targetUrl);
    response.setStatus(statusCode.value());
    response.setHeader("Location", encodedURL);
}

I had the same problem, but it was triggered by setting up tomcat behind a loadbalancer. The loadbalancer does the SSL handshake and forwards to tomcat a plain http connection.

Solution would be to send a special Http Header in your Loadbalancer, so tomcat can "trust" this connection. Using a servlet filter should set response.isSecure flag. Then overwrite RedirectView to see if response.isSecure and handle it the right way.

I kept this solution short because i am not sure if it machtes the question.

Solution 5 - Spring

Since Spring Boot 2.1 you have to add the following configuration to your application.properties:

server.use-forward-headers=true 

or application.yml:

server:
  use-forward-headers: true

Solution 6 - Spring

if you use springmvc ,you can try the following:

modelAndView.setView(new RedirectView("redirect url path", true, false));

Solution 7 - Spring

I add scheme="https" in file server.xml for connector with port="80":

<Connector port="80" protocol="HTTP/1.1" URIEncoding="UTF-8"
connectionTimeout="20000" redirectPort="443" scheme="https" />

Solution 8 - Spring

This started happening for us on Chrome 87 (https://blog.chromium.org/2020/08/protecting-google-chrome-users-from.html), for a quickfix to avoid the warning page in our springboot app we solve it by adding use-relative-redirects: true in the application.yml.

Solution 9 - Spring

I was also facing same issue...When redirecting it goes to http instead of HTTPS , below changes done :

RedirectView redirect = new RedirectView("/xyz",true);
redirect.setExposeModelAttributes(false);
redirect.setHttp10Compatible(false);
mav = new ModelAndView(redirect);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionsuper_aardvarkView Question on Stackoverflow
Solution 1 - Springsuper_aardvarkView Answer on Stackoverflow
Solution 2 - SpringtankthinksView Answer on Stackoverflow
Solution 3 - SpringAlbert BosView Answer on Stackoverflow
Solution 4 - SpringJanningView Answer on Stackoverflow
Solution 5 - SpringMichiel HaismaView Answer on Stackoverflow
Solution 6 - Springjoin chiView Answer on Stackoverflow
Solution 7 - Springerc mgddmView Answer on Stackoverflow
Solution 8 - SpringVijay YadavView Answer on Stackoverflow
Solution 9 - SpringKomalView Answer on Stackoverflow