Я пытаюсь создать реактивный @WebFilter
, который выполняет вещи до и после фактического обмена сервером (т. Е. Код контроллера, обрабатывающий запрос):
public static class Foobar implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
return Mono.empty()
.doOnEach(s -> /* BEFORE */))
.then(chain.filter(exchange) /* CONTROLLER */)
.and(Mono.empty().doOnEach(s -> /* AFTER */))
.and(Mono.empty().doFinally(s -> /* FINALLY */));
}
}
Все работает, как и ожидалось, для простых GET
запросов, которые возвращают Mono
:
@RestController
@RequestMapping
public static class Foo {
@GetMapping
@PostMapping(value = "foo")
public Mono<String> foo(ServerWebExchange exchange) {
return Mono.just("FOOBAR").map(e -> "OK");
}
}
Но что-то действительно неожиданное происходит, когда контроллер получает параметр, аннотированный как @RequestBody
. Скажем, например, запрос POST
, который получает Mono<String>
от клиента:
@RestController
@RequestMapping
public static class Bar {
@PostMapping(value = "bar")
public Mono<String> bar(ServerWebExchange exchange, @RequestBody Mono<String> text) {
return text.map(s -> "OK");
}
}
В этом случае все шаги в моем фильтре выполняются до того, как контроллер получит завершить запрос. Это означает, что веб-обмен выполняется независимо от фильтра, и поэтому я не могу ничего сделать сразу после отправки ответа клиенту.
Поэтому мне интересно:
- Это какая-то ошибка в Spring?
- Я что-то не так делаю?
- Или это просто ожидаемое поведение?
Я создал небольшой Gistсодержащий тестовый пример, который воспроизводит проблему:
Редактировать после комментария Брайана:
Я все еще думаю, что это может бытьошибка, потому что Mono.then
, кажется, не имеет никакого эффекта вообще:
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
return chain.filter(exchange)
.doOnSubscribe(s -> logger.info("onSubscribe response committed:" +
exchange.getResponse().isCommitted()))
.then().doOnEach(s -> logger.info("then doOnEach response committed:" +
exchange.getResponse().isCommitted()))
.doFinally(s -> logger.info("doFinally response committed:" +
exchange.getResponse().isCommitted()));
}
Кроме того, если я помещаю материал в doOnEach
, он тоже не выполняется:
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
return chain.filter(exchange)
.doOnSubscribe(s -> logger.info("FILTER-BEFORE-CHAIN/commited=" +
response.isCommitted()))
.doOnEach(s -> logger.info("FILTER-AFTER-CHAIN/commited=" +
response.isCommitted()))
.doFinally(s -> logger.info("FILTER-FINALLY/commited=" +
response.isCommitted()));
}