0

I'm hosting an Angular application inside a Spring Boot application.

Accessing routes like

is not an issue. However, if I access somthing below /profile:

I'll get an actual JSON responses, preventing the actual web-client to be loaded (see animation below).

After setting the debug-level on root to DEBUG, I saw the following:

:  GET "/profile", parameters={}
:  Mapped to org.springframework...ProfileController#listAllFormsOfMetadata()

and indeed, the code reaches org.springframework.data.rest.webmvc.ProfileController#listAllFormsOfMetadata() and I don't know how to disable this behavior or why this endpoint is being exposed in the first place.

Since Spring is exposing JPA-Repositories on default, I am already disabling this default behavior like so:

@Configuration
public class SpringRestConfiguration implements RepositoryRestConfigurer {
    @Override
    public void configureRepositoryRestConfiguration(
        RepositoryRestConfiguration config, CorsRegistry cors
    ) {
        config.disableDefaultExposure();
    }
}

How can I fix (disable) this behavior?

Animation

enter image description here

See also

Stefan Falk
  • 23,898
  • 50
  • 191
  • 378
  • What does the controller method that serves /profile and /profile/settings look like? Pls include imports, and class and method annotations. What does your security configuration look like? – John Williams Apr 17 '23 at 14:28
  • @JohnWilliams Well, there is no controller for these routes on the Spring Boot server. That's the weird part. I've added the `SecurityConfiguration` to my question. – Stefan Falk Apr 17 '23 at 14:32
  • is this link helpful for you ? https://stackoverflow.com/questions/50001285/angular-routing-doesnt-work-after-deploy-into-a-springboot-application – inkredusk Apr 17 '23 at 14:40
  • Understood. You are expecting to serve an angular page located in resources from /profile/settings, not a pure REST response. Perhaps there is something built in by SpringBoot that serves rest on /profile (profile is a very spring thing). Try renaming route in Angular to something very unlikely, eg /happydays to test the theory and whether the resourcehandler is behaving correctly. Your angular stuff is built/webpacked before dropping in resources/static? – John Williams Apr 17 '23 at 14:46
  • @JohnWilliams I've already tested this by visiting something like https://localhost:8081/sign-in or an invalid URL - it's only `/profile` that I know of right now which gives a JSON response. My guess is that is has something to do with JPA but I have no idea what it could be. – Stefan Falk Apr 17 '23 at 14:58

1 Answers1

0

Solution (Part 1)

In order to be able to refresh the Angular web-application at all, I had to add a resource handler which resolves non-existing/readable resources like so:

@Configuration
public class StaticWebConfig implements WebMvcConfigurer {

    /**
     * This is used to make page refreshes possible for the Angular App which runs on the root.
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {

        PathResourceResolver pathResourceResolver = new PathResourceResolver() {
            @Override
            protected Resource getResource(
                    @NotNull String resourcePath,
                    @NotNull Resource location
            ) throws IOException {
                Resource requestedResource = location.createRelative(resourcePath);
                boolean isValid = requestedResource.exists() && requestedResource.isReadable();
                return isValid ? requestedResource : new ClassPathResource("/static/index.html");
            }
        };

        registry.addResourceHandler("/**")
                .addResourceLocations("classpath:/static/")
                .resourceChain(false)
                .addResolver(pathResourceResolver);
    }    
}

Solution (Part 2)

Unfortunately, this is not enough for my particular case as the web-application has routes at and below /profile.

Spring Boot, for some reason, exposes some additional endpoints. Unfortunately, it appears that we cannot disable them programmatically (or at least not to my knowledge). The solution that should work (see further down below) does not work.

What we're left with is a workaround.

The workaround

This won't be an option for everyone but in my case it is. So far this will show the desired behavior.

spring:
  data:
    rest:
      # Spring Boot somehow exposes endpoints which interfere without web-application
      # It's not possible to work around this right now other than setting the base-path
      # of @BasePathAwareController classes to something else
      base-path: "/api-ignore-1337-only-took-me-one-day-to-figure-42"

The solution that should work and might work someday

@Override
public void configureRepositoryRestConfiguration(
        RepositoryRestConfiguration config, CorsRegistry cors
) {
    // Disable Alps resources
    config.getMetadataConfiguration().setAlpsEnabled(false);
}

Related issue on GitHub

Stefan Falk
  • 23,898
  • 50
  • 191
  • 378