0

I deployed a JAR for my REST API using Spring boot. The app also serves the React web app bundle through the /static directory.

The problem is that when I try to enter this link: http://SERVER-IP/password/change/1d0afe95-a643-437e-8307-ed7688b6a756

I see Whitelabel Error Page 404 message mapped instead of the expected page.

This issue isn't happening in my local environment, just in production (Ubuntu 16 vps).

Here is the code of my WebMvcConfig class:

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    private final long MAX_AGE_SECS = 3600;

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("HEAD", "OPTIONS", "GET", "POST", "PUT", "PATCH", "DELETE")
                .maxAge(MAX_AGE_SECS);
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/{spring:\\w+}")
                .setViewName("forward:/");
        registry.addViewController("/**/{spring:\\w+}")
                .setViewName("forward:/");
        registry.addViewController("/{spring:\\w+}/**{spring:?!(\\.js|\\.css)$}")
                .setViewName("forward:/");
    }

}

POM.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>XXX</groupId>
    <artifactId>XXX</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>XXX</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- For Working with Json Web Tokens (JWT) -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.0</version>
        </dependency>
        <!-- For Java 8 Date/Time Support -->
        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jsr310</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
            <version>2.0.1.RELEASE</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <executable>true</executable>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

And here is the javascript code for the routes:

export const routes = (
  <Switch>
    <PrivateRoute exact path="/" component={Routines} />
    <PrivateRoute exact path="/home" component={Routines} />
    <Route exact path="/login" component={Login} />
    <Route exact path="/signup" component={Signup} />
    <PrivateRoute exact path="/password/change" component={ChangePassword} />
    <Route exact path="/password/change/:token" component={ChangePassword} />
    <Route exact path="/password/reset" component={ResetPassword} />
    <Route component={NotFoundPage} />
  </Switch>
);

All other routes are working fine either by React routing or by inserting the URL in the browser

How can I do to forward all routes to index.html, even in production?

victor.ja
  • 811
  • 1
  • 7
  • 27

1 Answers1

0

The problem was the regexes at addViewControllers method in WebMvcConfig class.

In particular, \\w was only matching alphabets and numbers, but it wasn't matching hyphens. For a strange reason, which may be because of browser caching, it worked in the dev environment.

Here is the correct regex : ^[a-zA-Z\d-_] and below, the correct addViewControllers method:

@Override
public void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("/{spring:^[a-zA-Z\\d-_]+}")
            .setViewName("forward:/");
    registry.addViewController("/**/{spring:^[a-zA-Z\\d-_]+}")
            .setViewName("forward:/");
    registry.addViewController("/{spring:^[a-zA-Z\\d-_]+}/**{spring:?!(\\.js|\\.css)$}")
            .setViewName("forward:/");
}
victor.ja
  • 811
  • 1
  • 7
  • 27