Я использую 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.
Результат, кажется, правильныйобрабатывается, но только после того, как приложение было остановлено, результат отображается в клиенте.Каким-то образом транзакция не заканчивается до закрытия.Что-то нужно для подтверждения результата или текущий выбранный поток просто неверен?