Как получить URL текущего метода контроллера в Spring Webflux? - PullRequest
2 голосов
/ 18 марта 2019

Этот вопрос похож на Каков наилучший способ получить текущий URL в Spring MVC? , но для Webflux (это также может быть связано с Как получить контекст текущего запроса в spring-webflux но этот вопрос более конкретный, поэтому я надеюсь, что есть решение).

Что я хочу сделать, это получить текущий URL в контроллере Webflux. Например:

@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, если это имеет значение.

1 Ответ

2 голосов
/ 18 марта 2019

Вы можете использовать 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
)
...