Возврат ответа GZipped с помощью Spring Cloud Gateway застревает - PullRequest
0 голосов
/ 05 февраля 2019

Я использую Spring Cloud Gateway для пересылки запросов к серверной службе.Поскольку некоторые из наших внутренних сервисов отправляют свои результаты в формате gzip, хорошей идеей является определение глобального фильтра, который нужно разархивировать перед обработкой в ​​маршрутах, и повторной отправки gzip перед отправкой клиенту.Таким образом, нет необходимости делать это для каждого маршрута.Использование различных идей, связанных с переполнением стека, привело к следующему определению, чтобы сжать результат шагов обработки.

@Component
public class GlobalGZipFilter implements GlobalFilter, Ordered {

    private static final Logger log = LoggerFactory.getLogger(GlobalGZipFilter.class);

    @Override
    public int getOrder() {
        return -2; 
    }



    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        ServerHttpResponse originalResponse = exchange.getResponse();

        DataBufferFactory bufferFactory = originalResponse.bufferFactory();
        ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {

            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                log.info("Content should be GZipped: {}", isGZipped(originalResponse));
                if (isGZipped(originalResponse) && body instanceof Flux) {
                    Flux<? extends DataBuffer> flux = (Flux<? extends DataBuffer>) body;

                    return super.writeWith(flux.buffer().map(dataBuffers -> {
                        ByteOutputStream outputStream = new ByteOutputStream();
                        for (DataBuffer i : dataBuffers) {
                            byte[] array = new byte[i.readableByteCount()];
                            i.read(array);
                            outputStream.write(array);
                        }

                        String resultResponse = new String(outputStream.getBytes());

                        return bufferFactory.wrap(zipString(resultResponse));
                    }));
                }

                return super.writeWith(body); // if body is not a flux. never got there.
            }
        };

        return chain
                .filter(exchange
                        .mutate()
                        .response(decoratedResponse)
                        .build()); // replace response with decorator
    }

Поток состоит в том, чтобы собрать буферы, содержащие результат, преобразовать его в один полный byte[] и сжать это byte[], используя gzip.

Результат, кажется, правильныйобрабатывается, но только после того, как приложение было остановлено, результат отображается в клиенте.Каким-то образом транзакция не заканчивается до закрытия.Что-то нужно для подтверждения результата или текущий выбранный поток просто неверен?

1 Ответ

0 голосов
/ 06 февраля 2019

Проблема не столько в обработке потока или данных.Я забыл учесть, что при доставке содержимого, которое будет возвращено, длина ответа будет другой.Добавление длины содержимого на основе сжатого содержимого поможет:

  String resultResponse = new String(outputStream.getBytes());
                        byte[] zippedResponse = zipString(resultResponse);

                        originalResponse.getHeaders().setContentLength(zippedResponse.length);

                        return bufferFactory.wrap(zippedResponse);
...