So far (Spring Boot 1.5.4-RELEASE) I were using the configuration key server.contextPath of application.properties to change the context path of a Spring Boot based web application, as follows:

server.contextPath=/mypath

Unfortunately, this has stopped working when upgrading to Spring Boot 2.0.0-M3.

Is this a bug or this feature has changed in Spring Boot 2?

Comment From: wilkinsona

Configuring the context path is servlet-specific. To reflect that fact and avoid confusion when using WebFlux, the configuration property was renamed to server.servlet.context-path. That should have been mentioned in the M1 release notes but it looks like we missed it.

Comment From: wilkinsona

These are the changes that need to be described in the release notes: https://github.com/spring-projects/spring-boot/commit/12d883f6b9b022d305c7303871a44e4d6bd4fae4

Comment From: snicoll

@bonigarcia which IDE are you using? As of M4, it should show up in red

Comment From: wilkinsona

I've updated the release notes to describe the changes. Thanks for bringing this to our attention, @bonigarcia.

Comment From: bonigarcia

Thank you very much, using server.servlet.context-path my app is working again as expected.

@snicoll I am using Eclipse 4.7 (Oxygen), but without any specific Spring plugin (I think that way is impossible for the IDE to warn me about the problem)

Keep up the great work!

Comment From: danieldelatorre

Hello,

I am using spring boot 2.0.0.M4/7 and I used the server.servlet.context-path=/mypath but it dpes not work. I can reach my rest endpoints using the url without the path. Can you help me with this?

Comment From: danieldelatorre

Also I want to add that I am using webflux, maybe webflux does not support that property.

Comment From: philwebb

@danieldelatorre That property is only for servlet based deployments. I don't think we have an equivalent for webflux (do we @bclozel?).

Comment From: bclozel

In Spring Framework, there are several ways to deal with context paths:

  • deploying your WebFlux app as a war in a Servlet container and configure the Servlet to a particular context path. Spring Boot does not support WebFlux war deployment.
  • Spring Framework provides a ContextPathCompositeHandler that allows delegating to multiple HttpHandler instances depending on the path. With @EnableWebFlux, you can provide both WebFlux annotation and WebFlux functional handlers and they'll be mapped accordingly.

While we could leverage that last bit and map the whole WebFlux application to a particular context, I don't see the real added value since we don't deploy to war nor map multiple HttpHandler instances. We'd just have everything mapped under one path.

Comment From: danieldelatorre

ok thanks for the quick answer. One last question if I add to the pom.xml the spring-boot-starter-webflux and the spring-boot-starter-web the server.servlet.context-path works. If I add both references in the pom how can my service be impacted?

Comment From: bclozel

If you add both starters, your application is a Spring MVC app. Note that as of Spring Framework 5, Spring MVC knows how to handle a few cases with Flux at the controller level.

Comment From: danieldelatorre

But if my application is using Flux and Mono in the RestController, it will continue using non blocking calls right?

Comment From: bclozel

Short answer - asynchronous: yes, non-blocking: no. If you want the full story about why that is, we've just released the SpringOnePlatform talks and one of them is super relevant to your question.

If you've got more questions, please ask them on StackOverflow - the team is monitoring many tags there and questions are more likely to help the rest of the community.

Comment From: danieldelatorre

well thanks so much for your help

Comment From: remesh22

server.servlet.context-path only works with below dependency:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Since webflux is not supporting this property, i cannot provide context path for my tomcat webflux application. Because of this all my actuator endpoints are sitting at context root '/'. I don't want to deploy my application as a WAR file. Is there a way to support both my endpoints and actuator endpoints at the same context root rather than the default context root of '/' in webflux.

Comment From: adsanche

Here's what I'm doing to set the context path with Tomcat Reactive:

@Configuration
public class TomcatReactiveWebServerConfig extends TomcatReactiveWebServerFactory {

    @Value("${server.context-path}")
    private String contextPath;

    @Override
    protected void configureContext(final Context context) {
        super.configureContext(context);
        if (StringUtils.isNotBlank(this.contextPath)) {
            context.setPath(this.contextPath);
        }
    }
}

In application.properties:

server.context-path=/yourcontext

Comment From: denisw

I have a Spring Boot Webflux app behind a Kubernetes ingress, exposed under /api. This request prefix gets removed before reaching the Spring Boot application, so GET of https://app.example/api/foo will appear as GET /foo to the app.

Using such a setup, how can I ensure redirects take the /api prefix into account, without context path? Specifically, Spring Security's oauth2login breaks for me because visiting a protected route redirects to /oauth2/authorization/ciam, while it should really redirect to /oauth2/authorization/ciam.

Comment From: bclozel

@denisw Please ask questions on StackOverflow; if you believe this is a bug, you can create a new issue with a repro project we clone and run. Thanks!

Comment From: denisw

Sorry, maybe I wasn't clear. I commented here because I believe this to be a use case that makes the context path feature useful even outside of servlets, and perhaps should not be dismissed as done in #14082.

Comment From: bclozel

@denisw from your description, it doesn't sound like a context path feature but rather something like X-Forwarded-Path support.

Comment From: denisw

@bclozel You are right, I was able to cover my use case by:

  • Let the proxy add an X-Forwarded-Predix: /api header to requests
  • Defining a ForwardedHeaderTransformer bean named forwardedHeaderTransformer, which is automatically picked up by Webflux

Comment From: Numbernick

So to be honest we have the same problem. Our infrastructure is homogenous with servlet and webflux components. Our guideline for our ingres is to route to a specific context path. Sure I can workarround this with annotating ALL my Controllers with this prefix. An equivalent mechanism for reactive would be a good help for migrating. (Also this option exists for webflux for the actuator endpoint -> management.endpoints.web.base-path)

Comment From: zhouchong90

@denisw We have the same problem as you do using webflux with Kubernetes. Could you help to elaborate on your solution? Specifically how you added the X-Forwarded-Predix: /api header. I'd appreciate it if you could share your ingress yaml.

Comment From: philwebb

Reopening so we can investigate how difficult this will be.

Comment From: pgerhard

In order to use easily use Webflux in production we would also require this feature. All our backends are exposed to the outside world via a proxy and we route requests to the backends based on the requested URL. While it is possible to strip the prefix in the proxy, this results in the API endpoints changing between local development deployments and dev / staging / production deployments which needlessly complicates things for DevOps

Comment From: FearlessHyena

Same here. It would be really great to have this option

Comment From: pluttrell

Is this a safe and reliable work around until this feature gets implemented?

@Bean
@ConditionalOnProperty("server.servlet.context-path")
@Order(Ordered.HIGHEST_PRECEDENCE)
public WebFilter contextPathWebFilter(ServerProperties serverProperties) {

  String contextPath = serverProperties.getServlet().getContextPath();

  return (exchange, chain) -> {

    ServerHttpRequest request = exchange.getRequest();
    String requestPath = request.getURI().getPath();

    if (requestPath.startsWith(contextPath + "/") || requestPath.equals(contextPath)) {

      return
          chain.filter(
              exchange.mutate()
                  .request(request.mutate().contextPath(contextPath).build())
                  .build()
          );

    } else {
      throw new ResponseStatusException(HttpStatus.NOT_FOUND);
    }

  };

}

Based on https://stackoverflow.com/a/50998253/1930325.

Comment From: pgerhard

@pluttrell i did something very similar to yours and it worked fine until i started using spring security. my filter was being run the security chain had been finished processing which resulted in all sorts of funny errors. Most notably I ended up having issues with the redirection behaviour implemented by the security filter chain. Thats why I ended up including the filter at the very beginning of my security filter chain, instead of defining it as a "normal" filter bean

Comment From: philwebb

@springmarker @huodon Please use the "👍" reaction button on the initial comment if you're interested in the feature. Adding additional comments creates a lot of noise and makes it harder to follow the discussion.

Comment From: Prigovor

Hello. How to apply it to functional routers?

Comment From: bclozel

@Prigovor it should apply to all WebFlux handlers. If this is not the case, please create a new issue with a project reproducing the problem. Thanks!

Comment From: Prigovor

Thanks for instant reply. Will try to play with it else... ))

Comment From: codependent

@bclozel Will there be a 2.2.7 version before 2.3.0? In that case could this be backported to the 2.2.x branch?

Comment From: wilkinsona

@codependent Sorry, but we don't backport enhancements to maintenance branches. You'll have to wait for 2.3.0 (due next month) to pick this one up.

Comment From: lfcortes12

@bclozel I've created https://github.com/spring-projects/spring-boot/issues/22510 because it did not work for me.

Thanks