Есть ли способ отправить CONTENT_LENGTH вместе с контентом в реактор-нетты? - PullRequest
0 голосов
/ 03 июля 2019

Мой HttpServer отвечает на запросы http get с некоторым содержимым. Этот контент относительно небольшой, но его получение может занять некоторое время. Как я понимаю реактивный стек, я должен передать Mono или Flux HttpServerResponse, и мой сервис должен выполнять фоновую блокировку ввода-вывода в некоторых потоках, отличных от рабочих потоков Netty. Например:

class SomeService {
    private static final ExecutorService EXECUTOR = ...

    public Mono<String> load() {
        CompletableFuture<String> future = new CompletableFuture<>();
        EXECUTOR.submit(() -> loadContent(future));
        Mono<String> ret = Mono.fromFuture(future).onErrorResume(Mono::error);
        return ret;
    }

    private void loadContent(CompletableFuture<String> cf) {
        String s = doBlockingLoadFromSomewhere();
        cf.complete(s);
    }
}

class Server {
    private SomeService loader;

    void activate() {
        InetSocketAddress address = getAddressSomehow();
        server = HttpServer.create()
                .host(address.getHostString())
                .port(address.getPort())
                .route(routes -> routes.get("/path", this::handlePath))
                .bindNow();
    }

    private Publisher<Void> handlePath(HttpServerRequest request, HttpServerResponse response)
    {
        Mono<String> contentMono = loader.load();
        return response.status(OK).sendString(contentMono);
    }
}

Это прекрасно работает с одним исключением. Я должен отправить заголовок CONTENT_LENGTH, но реактор-нетто не устанавливает его автоматически, поэтому я должен сделать это сам. У меня есть очевидный способ блокировать и подсчитывать длину контента, когда он доступен, но он блокирует поток Netty. Я пытался составить весь NettyOutbound в Mono, но это полностью теряет контент, возможно, я сделал что-то не так.

    private Publisher<Void> handlePath(HttpServerRequest request, HttpServerResponse response)
    {
        Mono<String> contentMono = loader.load();
        Mono<NettyOutbound> handling = contentMono.flatMap(str -> {
            NettyOutbound r = response.status(OK)
                    .header(CONTENT_LENGTH, Long.valueOf(str.length()).toString())
                    .sendString(Mono.just(str), UTF_8);
            return Mono.just(r);
            });
        return handling.then();
    }

Пожалуйста, скажите мне, есть ли канонический способ отправки CONTENT_LENGTH (и вообще составление заголовков ответа на контент, который Mono готов) без блокировки рабочего потока Netty? Другими словами. Все образцы документации составляют заголовки ответа сразу и составляют контент в тот момент, когда он готов. Как я могу составить заголовки и контент ответа в тот момент, когда контент готов?

PS Я использую io.projectreactor: реактор-ядро: 3.2.5.RELEASE и io.projectreactor.netty: реактор-нетто: 0.8.4.RELEASE

...