Override the default redirect URL in a SpringMVC a

2020-06-06 04:59发布

问题:

I have a simple Spring MVC application that will redirect the user to a new page after certain controller actions. For example:

@Controller
public class ResponseController {
    @RequestMapping(value = "/save", method = RequestMethod.POST)
    public String saveObj(HttpServletRequest request, @ModelAttribute(“someObject”) Object obj) {
        // logic to validate and save object
        return "redirect:/obj/" + id;
    }
}

This Spring MVC application is running behind a loadbalancer with several other instances. Each have their own hostname. The loadbalancer is configured with SSL and the instances are not.

What I would like to know is the best practice to override the default redirect behavior. Currently, the application starts with https://mysite.com, but after a user performs an action that requires a redirect, the application redirects the user to http://some.hostnameX.com.

Currently, I have a property that is used to help redirect the user to mysite.com.

loadbalancer.url=https://mysite.com

Then, in the controller, I have the following:

@Value("loadbalancer.url")
String loadbalanerUrl;

@RequestMapping(value = "/save", method = RequestMethod.POST)
public String saveObj(HttpServletRequest request, @ModelAttribute(“someObject”) Object obj){
    // logic to validate and save object
    return "redirect:" + loadbalancerUrl + "/obj/" + id;
}

Is there a better way to override this behavior?

回答1:

The redirect behavior can be found in org.springframework.web.servlet.view.UrlBasedViewResolver. You can easily alter this behavior by extending any subclass or the class itself and add it to the application context.

You could for example write a special condition that will prepend the url in a redirect view name. It will eliminate the need to do it manually.

public class CustomUrlBasedViewResolver extends UrlBasedViewResolver {
    @Value("${loadbalancer.url}")
    private String loadBalancerUrl;

    @Override
    protected View createView(String viewName, Locale locale) throws Exception {
        if (viewName.startsWith(super.REDIRECT_URL_PREFIX)) {
            String url = viewName.substring(REDIRECT_URL_PREFIX.length());
            String loadBalancedViewName = super.REDIRECT_URL_PREFIX + loadBalancerUrl + url;

            return super.createView(loadBalancedViewName, locale);
        }
        return super.createView(viewName, locale);
    }
}


回答2:

You can also set this on each instance (in their own app.properties or app.yml):

server.use-forward-headers=true

Doing this the HttpServletRequest object will get the load balancer host, as well as its port.