Spring WebFlux WebFilter问题:响应体修改不生效
问题原因及解决方案
你的过滤器逻辑存在两个关键问题,导致修改后的响应无法正确返回给客户端:
- 仅处理了单元素响应体(Mono):如果响应体是
Flux<DataBuffer>(比如流式响应),Mono.from(body)只会取第一个DataBuffer,剩余内容会丢失,同时原始响应内容可能已被部分写入客户端。 - 未更新响应头的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
相关产品推荐
相关产品推荐

