Marcus Lindwall
Marcus Lindwall

Reputation: 325

Context Path with Webflux

I've been trying to find a way to set the context path for a webflux application. I know I can configure it using

server.servlet.context-path

if I deploy a servlet, but I would like to achieve it with webflux, without having to explicitly add the path to every route or use MVC.

Upvotes: 30

Views: 30547

Answers (12)

phancuongviet
phancuongviet

Reputation: 435

You can try this solution, hope to help you.

https://github.com/spring-projects/spring-boot/issues/22162

In my situation I follow the suggestion step by step as below

  1. Add both spring-boot-starter-web and spring-boot-starter-webflux to pom.xml
  2. Add spring.webflux.base-path=/service-name
  3. Update main class of spring boot application

SpringApplication springApplication = new SpringApplication(DscUserManagementService.class); springApplication.setWebApplicationType(WebApplicationType.REACTIVE); springApplication.run(args);

  1. Finally, let try API ip:port/service-name/...

Thank you wilkinsona

Upvotes: 1

Spring webflux version 2.3.4.RELEASE

need two elements, first declare a bean for enable weflux properties

@Bean public WebFluxProperties webFluxProperties(){
return new WebFluxProperties(); 
}

Second define the correct path

spring.webflux.base-path = mypath

Upvotes: 1

georgep
georgep

Reputation: 81

I was facing a similar issue with the spring.webflux.base-path (which didn't seem to be working as expected) in webflux-reactive-spring-web and I realized that I had autoconfiguration disabled.

A manually workaround is:

@Bean
public WebFluxProperties webFluxProperties(){
    return new WebFluxProperties();
}

Upvotes: 8

Luv
Luv

Reputation: 199

You can use web Filter, as mentioned in above answers, but you can do one more thing. Write a Base Controller and Extend every class to that Base Controller. For example:

Base Controller.java

@RestController
@RequestMapping("/{base_url}")
public abstract class BaseController {
}

NewController.java

@RestController
public class NewController extends BaseController{
  @Autowired
  DatabaseClient databaseClient;

  @GetMapping("/status")
  public Mono<Map<String, String>> status() {
    return databaseClient.execute("SELECT 'ok'").
      map(row -> singletonMap("status", row.get(0, String.class)))
      .one();
  }
}

So now you can hit /{base_url}/status

Upvotes: 1

Abudzar Al-Ghiffari
Abudzar Al-Ghiffari

Reputation: 815

According to this

There is servlet in the name of the property which should be a hint that won't work with webflux.

With springboot v2.3, you can put this in your properties file

spring.webflux.base-path=/your-path

release-notes reference: https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.3-Release-Notes#configurable-base-path-for-webflux-applications

Upvotes: 66

bitbyteboi
bitbyteboi

Reputation: 11

Here is an example of configuring the context path for WebFlux using Netty server based on a comment by @Dmytro Boichenko. You can also include customizers to configure the port and other properties.

@Configuration
public class NettyServerConfig {

    @Value("${server.port}")
    private int port;

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

    @Bean
    public NettyReactiveWebServerFactory nettyReactiveWebServerFactory() {
            NettyReactiveWebServerFactory webServerFactory = new NettyReactiveWebServerFactory() {
                @Override
                public WebServer getWebServer(HttpHandler httpHandler) {
                    Map<String, HttpHandler> handlerMap = new HashMap<>();
                    handlerMap.put(contextPath, httpHandler);
                    return super.getWebServer(new ContextPathCompositeHandler(handlerMap));
                }
        };
        webServerFactory.addServerCustomizers(portCustomizer());
        return webServerFactory;
    }

    public NettyServerCustomizer portCustomizer() {
        return new NettyServerCustomizer() {
            @Override
            public HttpServer apply(HttpServer httpServer) {
                return httpServer.port(port);
            }
        };
    }
}

Upvotes: 1

pixel
pixel

Reputation: 26513

For use cases where WebFlux application is behind load balancer/proxy you can use dedicated class - ForwardedHeaderTransformer that will extract path context from X-Forwarded-Prefix and will add it to ServerHttpRequest.

Doing so you won't need to modify global context-path (which does not make sense in WebFlux)

More about it here: https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-web-handler-api

Upvotes: 2

刘家华
刘家华

Reputation: 191

You can use web filter to make WebFlux support contextPath

@Bean
public WebFilter contextPathWebFilter() {
    String contextPath = serverProperties.getServlet().getContextPath();
    return (exchange, chain) -> {
        ServerHttpRequest request = exchange.getRequest();
        if (request.getURI().getPath().startsWith(contextPath)) {
            return chain.filter(
                exchange.mutate()
                .request(request.mutate().contextPath(contextPath).build())
                .build());
        }
        return chain.filter(exchange);
    };
}

Upvotes: 16

Sancho
Sancho

Reputation: 437

Here's my way of doing it with Tomcat Reactive:

@Configuration
public class TomcatReactiveWebServerConfig extends TomcatReactiveWebServerFactory {

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

    /**
     * {@inheritDoc}
     */
    @Override
    protected void configureContext(final Context context) {

        super.configureContext(context);

        if (StringUtils.isNotBlank(this.contextPath)) {
            context.setPath(this.contextPath);
        }
    }
}

Upvotes: 4

J&#252;rgen Obernolte
J&#252;rgen Obernolte

Reputation: 359

For Undertow I managed to add a context path by creating a customized UndertowReactiveWebServerFactory:

 @Bean
public UndertowReactiveWebServerFactory undertowReactiveWebServerFactory(
        @Value("${server.servlet.context-path}") String contextPath) {
    return new UndertowReactiveWebServerFactory() {
        @Override
        public WebServer getWebServer(HttpHandler httpHandler) {
            Map<String, HttpHandler> handlerMap = new HashMap<>();
            handlerMap.put(contextPath, httpHandler);
            return super.getWebServer(new ContextPathCompositeHandler(handlerMap));
        }
    };
}

Upvotes: 3

Hieu Nguyen
Hieu Nguyen

Reputation: 11

I was having the same issue since the loader balancer bases on the context path to route to different back end apps. One way to get around Spring Boot Webflux w/ the context path is using variables in the @XXXXMapping annotations. For instance @RequestMapping(value = "${server.servlet.context-path}/subpath")

Upvotes: 0

Brian Clozel
Brian Clozel

Reputation: 59221

If you are configuring yourself the server (if you’re not using Spring Boot), you can setup a ContextPathCompositeHandler that wraps several handlers itself.

If you are using Spring Boot, this feature is not supported currently.

Upvotes: 0

Related Questions