Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get URL of the current controller method in Spring Webflux?

This question is similar to What's the best way to get the current URL in Spring MVC? but for Webflux (it might also be related to How to get the context of the current request in spring-webflux but this question is more specific so I'm hoping there's a solution).

What I want to do is to get a hold of the current URL in a Webflux controller. For example:

@GetMapping("/greeting")
public Mono<Greeting> greeting() {
   String linkToCurrentResource = .. // How do I get this?
   Greeting greeting = new Greeting("hello",  linkToCurrentResource);
   return Mono.just(greeting);
}

Preferably linkToCurrentResource should understand X-Forwarded-??? headers if running behind a load balancer. So in this case the I'd like linkToCurrentResource to be something like https://external-uri.com/api/greeting. I'm using the Netty server implementation if that matters.

like image 336
Johan Avatar asked Oct 23 '25 17:10

Johan


1 Answers

You can use the ServerHttpRequest as a method parameter to get the uri:

@RestController
public class GreetingController {
  @GetMapping("/greeting")
  public Mono<Greeting> getGreeting(ServerHttpRequest serverHttpRequest) {
    return Mono.just(new Greeting("greeting", serverHttpRequest.getURI().toString()));
  }
}

Preferably linkToCurrentResource should understand X-Forwarded-??? headers if running behind a load balancer.

Then you can expose a ForwardedHeaderTransformer @Bean.

From its documentation:

Extract values from "Forwarded" and "X-Forwarded-*" headers to override the request URI (i.e. HttpRequest.getURI()) so it reflects the client-originated protocol and address.

@Configuration
open class MvcConfig {
    @Bean
    open fun forwardedHeaderTransformer() = ForwardedHeaderTransformer()
}

Here are some tests:

@ExtendWith(SpringExtension::class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT,
        properties = ["server.port=4333"])
class GreetingController2Test {
    @Autowired
    private lateinit var restTemplate: TestRestTemplate

    @Test
    fun `should return uri`() {
        val responseEntity = restTemplate.getForEntity("/greeting", Greeting::class.java)
        val greeting = responseEntity.body!!
        assertEquals("http://localhost:4333/greeting", greeting.uri)
    }

    @Test
    fun `should return uri composed from forwarded-??? headers`() {
        val headers = HttpHeaders()
        headers["X-Forwarded-Host"] = "external-uri.com"
        headers["X-Forwarded-Proto"] = "https"
        headers["X-Forwarded-Prefix"] = "/prefix"

        val httpEntity = HttpEntity(null, headers)
        val responseEntity = restTemplate.exchange("/greeting", HttpMethod.GET, httpEntity, Greeting::class.java)
        val greeting = responseEntity.body!!
        assertEquals("https://external-uri.com/prefix/greeting", greeting.uri)
    }
}

And the Greeting.kt:

data class Greeting(
        val g: String? = null,
        val uri: String? = null
)
like image 148
Denis Zavedeev Avatar answered Oct 26 '25 09:10

Denis Zavedeev



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!