使用Spring Cloud Gateway返回GZipped响应卡住了

时间:2019-02-05 15:50:34

标签: spring-cloud-gateway

我正在使用Spring Cloud Gateway将请求转发到后端服务。由于我们的某些后端服务以gzip格式发送其结果,因此定义一个全局过滤器以便在处理路由之前解压缩,然后再将gzip发送给客户端之前似乎是个好主意。这样,就不必为每条路线都这样做。使用关于Stack Overflow的各种想法得出以下定义,以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[]并使用gzip压缩此byte[]

结果似乎已正确处理,但只有在应用程序停止后,结果才会显示在客户端中。交易以某种方式在结束之前不会结束。是否需要确认结果或当前选择的流量不正确?

1 个答案:

答案 0 :(得分:0)

在处理助焊剂或数据时,问题并不多。我忘记考虑的是,将要返回的内容压缩到gzip时,回复的长度会有所不同。根据压缩后的内容添加内容长度将达到目的:

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

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

                        return bufferFactory.wrap(zippedResponse);