8

I am trying to make use of Tomcat's rewrite valve in my Spring Boot app however cannot determine where to put the rewrite.conf in order to be loaded successfully.

I am using Spring Boot 2.0.3.RELEASE with Tomcat 8.5.31 and packaging the application as a fat jar.

I have configured the rewrite valve like so:

@Bean
public TomcatServletWebServerFactory containerFactory() {
    TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
    factory.addContextValves(new RewriteValve());

    return factory;
}

However, it appears to rely on a directory structure of /WEB-INF to load the rewrite.conf from, which being a fat jar, I don't currently have.

Has anybody found a solution to configure this without changing the application packaging structure to a WAR with a WEB-INF directory?

dapperwaterbuffalo
  • 2,672
  • 5
  • 35
  • 48

3 Answers3

5

With spring boot 2 and tomcat embedded.

First create rewrite.config file under resources directory like this resources/rewrite.config. This rule example for run routing react in my server side (react needs to redirect all routes to index.html)

RewriteCond %{REQUEST_URI} !^.*\.(bmp|css|gif|htc|html?|ico|jpe?g|js|pdf|png|swf|txt|xml|svg|eot|woff|woff2|ttf|map)$
RewriteRule ^(.*)$ /index.html [L]

then create your own custom class for configure tomcat server like this:

@Component
public class CustomContainer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {

    @Override
    public void customize(TomcatServletWebServerFactory factory) {

        final RewriteValve valve = new RewriteValve() {

            @Override
            protected synchronized void startInternal() throws LifecycleException {
                super.startInternal();

                try {
                    InputStream resource = new ClassPathResource("rewrite.config").getInputStream();

                    InputStreamReader resourceReader = new InputStreamReader(resource);
                    BufferedReader buffer = new BufferedReader(resourceReader);

                    parse(buffer);

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        };

        valve.setEnabled(true);

        factory.addContextValves(valve);
    }
} 

This custom class overrides starInternal method to implement how to retrieve the config file for parsing it and add that valve in context valves.

This work fine for me :)

G.chakib
  • 84
  • 1
  • 4
2

The problem is that you are configuring the Factory, so creating and calling setConfiguration() will result in an NPE. So I extended that class with the rules in constructor and once startInternal() is called, the rules are processed.

Hope this helps, Jan

public class LazySpringRewriteValve extends RewriteValve {

    private String unProcessedRules = "";

    @Override
    protected synchronized void startInternal() throws LifecycleException {
        setState(LifecycleState.STARTING);
        context = (getContainer() instanceof Context);
        try {
            this.setConfiguration(unProcessedRules);
        } catch (Exception e) {
            throw new LifecycleException(e);
        }
    }

    public LazySpringRewriteValve(String unProcessedRules){
        super();
        this.unProcessedRules = unProcessedRules;
    }
}
Alunisiira
  • 21
  • 3
-2

Try placing WEB-INF/rewrite.config in src/main/resources/META-INF/resources/.

Pang
  • 9,564
  • 146
  • 81
  • 122