这个问题类似于What's the best way to get the current URL in Spring MVC?,但是对于Webflux(它可能也与How to get the context of the current request in spring-webflux有关,但是这个问题更具体,所以我希望有一个解决方案)。
我要做的是在Webflux控制器中保留当前URL。例如:
@GetMapping("/greeting")
public Mono<Greeting> greeting() {
String linkToCurrentResource = .. // How do I get this?
Greeting greeting = new Greeting("hello", linkToCurrentResource);
return Mono.just(greeting);
}
如果在负载均衡器后面运行,最好
linkToCurrentResource
应该理解X-Forwarded-???
标头。因此,在这种情况下,我希望linkToCurrentResource
成为https://external-uri.com/api/greeting
之类的东西。如果这很重要,我正在使用Netty服务器实现。 最佳答案
您可以使用ServerHttpRequest
作为方法参数来获取uri
:
@RestController
public class GreetingController {
@GetMapping("/greeting")
public Mono<Greeting> getGreeting(ServerHttpRequest serverHttpRequest) {
return Mono.just(new Greeting("greeting", serverHttpRequest.getURI().toString()));
}
}
如果在负载均衡器后面运行,最好
linkToCurrentResource
应该理解X-Forwarded-???
标头。然后,您可以公开
ForwardedHeaderTransformer
@Bean
。从其文档中:
从“
Forwarded
”和“ X-Forwarded-*
”标头中提取值以覆盖请求URI
(即HttpRequest.getURI()
),以便它反映客户端起源的协议和地址。@Configuration
open class MvcConfig {
@Bean
open fun forwardedHeaderTransformer() = ForwardedHeaderTransformer()
}
以下是一些测试:
@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)
}
}
和
Greeting.kt
:data class Greeting(
val g: String? = null,
val uri: String? = null
)