为什么在调用 .block() 时反应器上下文抛出 "Context does not contain key"?
Why is reactor context throwing "Context does not contain key" when .block() is called?
我有一个 WebFilter
注入上下文
public class MyWebFilter implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
return chain.filter(exchange)
.contextWrite(ctx -> ctx.put("context", "some-context"));
}
}
在我的控制器中,我可以读取它并且return它成功
@RestController
public class MyController {
@GetMapping(path = "test")
public Mono<String> test() {
return Mono.deferContextual(ctx -> Mono.just(ctx.get("context")));
}
}
但是,如果我在上面调用 .block()
:
Mono.deferContextual(ctx -> Mono.just(ctx.get("context"))).block();
它抛出这个异常
java.util.NoSuchElementException: Context does not contain key: context
我无法理解反应世界中的执行顺序。
您会希望 Spring 尽可能 'realistically' 处理此问题。创建一个测试并使用 WebTestClient
。 (不要调用 .block()
ever 否则你会拒绝服务你的服务器 w/a 半打用户。不要 inject/call 你的控制器方法直接,你需要所有的代理、过滤器等)
这是科特林,但你应该能够理解它:
@SpringBootApplication
class WebfluxScratchpadApplication {
@Bean
fun filter(): WebFilter = WebFilter { serverWebExchange, webFilterChain ->
webFilterChain.filter(serverWebExchange)
.contextWrite {
it.put("myContextKey", "!!")
}
}
}
@RestController
class MyController {
@GetMapping("/foo")
fun foo() = Mono.just("foo")
.flatMap { s ->
Mono.deferContextual { ctx ->
Mono.just(String.format("%s%s", s, ctx["myContextKey"]))
}
}
}
fun main(args: Array<String>) {
runApplication<WebfluxScratchpadApplication>(*args)
}
@WebFluxTest
class WebfluxScratchpadApplicationTests {
@Autowired
lateinit var client: WebTestClient
@Test
fun stuff() {
Assertions.assertEquals(
"foo!!",
client.get()
.uri("/foo")
.exchange()
.expectBody<String>()
.returnResult()
.responseBody!!
)
}
}
当您调用 .block() 时,该行会立即被订阅和评估,与外链中提供的上下文没有任何联系。当你 return 没有 .block 时,它会成为具有上下文的更大链的一部分,并且不会被评估,直到某些东西订阅了外部链,此时上下文可用。
我有一个 WebFilter
注入上下文
public class MyWebFilter implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
return chain.filter(exchange)
.contextWrite(ctx -> ctx.put("context", "some-context"));
}
}
在我的控制器中,我可以读取它并且return它成功
@RestController
public class MyController {
@GetMapping(path = "test")
public Mono<String> test() {
return Mono.deferContextual(ctx -> Mono.just(ctx.get("context")));
}
}
但是,如果我在上面调用 .block()
:
Mono.deferContextual(ctx -> Mono.just(ctx.get("context"))).block();
它抛出这个异常
java.util.NoSuchElementException: Context does not contain key: context
我无法理解反应世界中的执行顺序。
您会希望 Spring 尽可能 'realistically' 处理此问题。创建一个测试并使用 WebTestClient
。 (不要调用 .block()
ever 否则你会拒绝服务你的服务器 w/a 半打用户。不要 inject/call 你的控制器方法直接,你需要所有的代理、过滤器等)
这是科特林,但你应该能够理解它:
@SpringBootApplication
class WebfluxScratchpadApplication {
@Bean
fun filter(): WebFilter = WebFilter { serverWebExchange, webFilterChain ->
webFilterChain.filter(serverWebExchange)
.contextWrite {
it.put("myContextKey", "!!")
}
}
}
@RestController
class MyController {
@GetMapping("/foo")
fun foo() = Mono.just("foo")
.flatMap { s ->
Mono.deferContextual { ctx ->
Mono.just(String.format("%s%s", s, ctx["myContextKey"]))
}
}
}
fun main(args: Array<String>) {
runApplication<WebfluxScratchpadApplication>(*args)
}
@WebFluxTest
class WebfluxScratchpadApplicationTests {
@Autowired
lateinit var client: WebTestClient
@Test
fun stuff() {
Assertions.assertEquals(
"foo!!",
client.get()
.uri("/foo")
.exchange()
.expectBody<String>()
.returnResult()
.responseBody!!
)
}
}
当您调用 .block() 时,该行会立即被订阅和评估,与外链中提供的上下文没有任何联系。当你 return 没有 .block 时,它会成为具有上下文的更大链的一部分,并且不会被评估,直到某些东西订阅了外部链,此时上下文可用。