Spring WebFlux - statusCode является нулевым в WebFilter - PullRequest
0 голосов
/ 05 октября 2018

В настоящее время разрабатывается с помощью Spring Boot 2.0.4 веб-фильтр, который регистрирует HTTP-запросы и информацию об ответах (URL, код состояния ответа, продолжительность и т. Д.) В приложении Spring WebFlux.

Работает нормально, за исключением этого exchange.getResponse (). getStatusCode () остается нулевым Второй:

    Mono<Void> filtered = chain.filter(exchange);
    exchange.getResponse().beforeCommit(() -> {
        System.out.println("Status=" + exchange.getResponse().getStatusCode());
        return Mono.empty();
    });
    return filtered;

Также пробовал различные заказы на фильтре: нет, @Order (100000), @Order (-100000).

Код состояния остается нулевым.

Какая правильная реализация?

Обновление 1

Написал минималистичный рабочий пример на основе решения KevH, см. https://github.com/fbeaufume/webflux-filter-sample, но этоеще не работает, статус все еще нулевой.MWE предоставляет две конечные точки REST: / hello и / pause / 1000 (пауза в 1 секунду).

Обратите внимание, что при вызове журналов конечной точки паузы:

11:06:20.644  INFO 9536 --- [ctor-http-nio-2] com.adeliosys.sample.LogFilter           : Request [/pause/1000] started, traceId [bb3fe67d-170b-4070-837d-816fe1420a1f]
11:06:20.673  INFO 9536 --- [ctor-http-nio-2] com.adeliosys.sample.HelloController     : Pausing for 1000 msec
11:06:21.683  INFO 9536 --- [     parallel-2] com.adeliosys.sample.LogFilter           : Request [/pause/1000] completed, statusCode [null], time [1039], traceId [bb3fe67d-170b-4070-837d-816fe1420a1f]
11:06:21.684  INFO 9536 --- [     parallel-2] com.adeliosys.sample.HelloController     : Paused for 1000 msec

Я удивлен, чтовторое сообщение фильтра отображается перед вторым сообщением конечной точки.

обновление 2

Кажется, что реализация фильтра использует doAfterTerminate(или аналогичные методы) были правильными, но это корректно возвращает статус ответа HTTP только с методами контроллера REST, которые используют ResponseEntity в типе возврата.

Не поддерживается(т. е. статус равен нулю): void, Mono<Void>, String, Mono<String>, MyBean, Mono<MyBean> и т. д.

Поддерживается (т. е. статус 200): ReponseEntity<Void>, Mono<ResponseEntity<Void>>, ReponseEntity<String>, Mono<ResponseEntity<String>>, ReponseEntity<MyBean>, Mono<ResponseEntity<MyBean>> и т. Д.

Ошибка?

Spring Boot 2.0.5 работает аналогично.

Обновление 3

Открыл вопрос по теме, см. https://jira.spring.io/browse/SPR-17368

1 Ответ

0 голосов
/ 06 октября 2018

Вы можете попробовать doAfterSuccessOrError

@Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        String traceId = UUID.randomUUID().toString();
        long startTime = System.currentTimeMillis();
        String path = exchange.getRequest().getURI().getPath();
        System.out.printf("Request[%s] started, trace_id[%s]", path, traceId);

        return chain.filter(exchange)
                .doAfterSuccessOrError((r, t) -> {
                    System.out.printf("Request[%s], completed, status_code[%s], time[%d], trace_id[%s]", path,
                            exchange.getResponse().getStatusCode(), System.currentTimeMillis() - startTime, traceId);
                })
                .subscriberContext(Context.of(String.class, traceId));
    }

пример вывода

Запрос [/ logrequest] запущен, trace_id [b45b550a-b9ad-4323-a850-cb085a78a086] Запрос [/ logrequest], завершено, код_состояния [202], время [41], trace_id [b45b550a-b9ad-4323-a850-cb085a78a086]

edit: точно не знаю, почему это не работает, но вотдва обходных пути оба имеют ResponseEntity

@GetMapping("/hello")
    public Mono<ResponseEntity<String>> publicHello() {
        return Mono.just(ResponseEntity.ok("Hello world!"));
    }

    @GetMapping("/pause/{duration}")
    @ResponseStatus(HttpStatus.ACCEPTED)
    public Mono<Void> pause2(@PathVariable long duration) {
        LOGGER.info("Pausing for {} msec", duration);
        return (duration > 0 ? Mono.delay(Duration.ofMillis(duration)) : Mono.empty())
                .then()
                .doFinally(s -> LOGGER.info("Paused for {} msec", duration));
    }
...