4

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.

1 Answer 1

12

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 ) 
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks A LOT! I couldn't have hoped for better answer. Works like a charm.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.