【问题标题】:Returning a GZipped response using Spring Cloud Gateway gets stuck使用 Spring Cloud Gateway 返回 GZipped 响应被卡住
【发布时间】:2019-06-29 11:54:08
【问题描述】:

我正在使用 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[]

结果似乎得到了正确处理,但只有在应用程序停止后,结果才会显示在客户端中。不知何故,交易并没有在关闭前结束。是否需要确认结果或当前选择的流程不正确?

【问题讨论】:

    标签: spring-cloud-gateway


    【解决方案1】:

    问题不在于通量或数据的处理。我忘记考虑的是,当 gzip 压缩要返回的内容时,回复的长度会有所不同。根据 gzip 压缩的内容添加内容长度就可以了:

      String resultResponse = new String(outputStream.getBytes());
                            byte[] zippedResponse = zipString(resultResponse);
    
                            originalResponse.getHeaders().setContentLength(zippedResponse.length);
    
                            return bufferFactory.wrap(zippedResponse);
    

    【讨论】:

      猜你喜欢
      • 2018-07-19
      • 1970-01-01
      • 2015-12-04
      • 2018-07-06
      • 2021-05-24
      • 2019-10-06
      • 2020-07-13
      • 2017-04-13
      • 2020-07-19
      相关资源
      最近更新 更多