You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring WebFlux WebFilter问题:响应体修改不生效

问题原因及解决方案

你的过滤器逻辑存在两个关键问题,导致修改后的响应无法正确返回给客户端:

  1. 仅处理了单元素响应体(Mono):如果响应体是Flux<DataBuffer>(比如流式响应),Mono.from(body)只会取第一个DataBuffer,剩余内容会丢失,同时原始响应内容可能已被部分写入客户端。
  2. 未更新响应头的Content-Length:修改响应内容后,内容长度发生变化,但原始的Content-Length头仍为原始值,客户端会据此截断响应,导致看不到修改后的内容。

修改后的完整代码如下:

@Component
public class EncryptionFilter implements WebFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        Decorator decorator = new Decorator(exchange.getResponse());
        return chain.filter(exchange.mutate().response(decorator).build());
    }

    public class Decorator extends ServerHttpResponseDecorator {
        public Decorator(ServerHttpResponse delegate) {
            super(delegate);
        }

        @Override
        public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
            // 将响应体转为Flux,确保所有DataBuffer都被处理
            return Flux.from(body)
                    // 收集所有缓冲区内容,同时释放原始缓冲区避免内存泄漏
                    .collectList()
                    .map(dataBuffers -> {
                        int totalLength = dataBuffers.stream().mapToInt(DataBuffer::readableByteCount).sum();
                        byte[] allContent = new byte[totalLength];
                        int offset = 0;
                        for (DataBuffer buffer : dataBuffers) {
                            int readable = buffer.readableByteCount();
                            buffer.read(allContent, offset, readable);
                            offset += readable;
                            DataBufferUtils.release(buffer);
                        }
                        // 修改响应内容
                        String originalContent = new String(allContent, StandardCharsets.UTF_8);
                        String modifiedContent = originalContent + " Modified";
                        return getDelegate().bufferFactory().wrap(modifiedContent.getBytes(StandardCharsets.UTF_8));
                    })
                    // 更新响应头:移除原始Content-Length,设置新的内容长度
                    .doOnNext(modifiedBuffer -> {
                        getDelegate().getHeaders().remove(HttpHeaders.CONTENT_LENGTH);
                        getDelegate().getHeaders().setContentLength(modifiedBuffer.readableByteCount());
                    })
                    // 将修改后的缓冲区写入响应
                    .flatMap(modifiedBuffer -> super.writeWith(Mono.just(modifiedBuffer)));
        }

        // 覆盖writeAndFlushWith,确保流式刷写场景也被处理
        @Override
        public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
            return super.writeAndFlushWith(Flux.from(body).map(this::writeWith));
        }
    }
}

关键改动说明

  • 兼容所有响应体类型:用Flux.from(body)替代Mono.from(body),确保流式响应能被完整处理。
  • 释放原始缓冲区:遍历原始DataBuffer时调用DataBufferUtils.release(buffer),避免WebFlux内存泄漏。
  • 更新响应头:移除或重设Content-Length,让客户端能正确接收完整的修改后内容。
  • 覆盖writeAndFlushWith:处理需要分段刷写响应的场景,确保所有响应类型都被拦截修改。

内容的提问来源于stack exchange,提问作者Ahatius

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 14:05:18