如何在Spring Webflux中获取当前控制器方法的URL?
How to get URL of the current controller method in Spring Webflux?
这个问题类似于 What's the best way to get the current URL in Spring MVC? but for Webflux (it might also be related to 但这个问题更具体所以我希望有一个解决方案)。
我想做的是在 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-???
headers 如果运行 在负载均衡器后面。所以在这种情况下,我希望 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()));
}
}
Preferably linkToCurrentResource
should understand X-Forwarded-???
headers if running behind a load balancer.
那你可以暴露一个ForwardedHeaderTransformer
@Bean
.
来自其文档:
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()
}
这里有一些测试:
@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
)
这个问题类似于 What's the best way to get the current URL in Spring MVC? but for Webflux (it might also be related to
我想做的是在 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-???
headers 如果运行 在负载均衡器后面。所以在这种情况下,我希望 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()));
}
}
Preferably
linkToCurrentResource
should understandX-Forwarded-???
headers if running behind a load balancer.
那你可以暴露一个ForwardedHeaderTransformer
@Bean
.
来自其文档:
Extract values from "
Forwarded
" and "X-Forwarded-*
" headers to override the requestURI
(i.e.HttpRequest.getURI()
) so it reflects the client-originated protocol and address.
@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
)