Spring Boot Webflux中如何完整克隆含Body的ServerResponse?
解决方案:在Spring Boot 2.0.1 Functional Endpoint中克隆ServerResponse并添加自定义头
针对你在Spring Boot 2.0.1.RELEASE + Functional Endpoint场景下,想通过过滤器给所有响应加自定义头但无法复制响应体的问题,我有几个实用的解决方案:
方案1:使用ExchangeFilterFunction(推荐)
ExchangeFilterFunction是WebFlux Functional模式下专门用于请求/响应拦截的组件,我们可以通过它拦截响应,读取原始响应体后重新构建带自定义头的响应。
实现自定义过滤器
import org.springframework.web.reactive.function.server.ExchangeFilterFunction; import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Mono; public class CustomHeaderFilter { public static ExchangeFilterFunction addCustomResponseHeader() { // 拦截响应处理逻辑 return ExchangeFilterFunction.ofResponseProcessor(originalResponse -> { // 读取原始响应体(这里以String为例,若为JSON对象可替换为对应DTO类型) return originalResponse.bodyToMono(String.class) .flatMap(responseBody -> { // 构建新的ServerResponse:复制原始状态码、响应头,添加自定义头,写入原始响应体 return ServerResponse.status(originalResponse.statusCode()) .headers(headers -> { headers.addAll(originalResponse.headers().asHttpHeaders()); headers.add("X-Custom-Header", "Your-Custom-Value"); }) .bodyValue(responseBody); }); }); } }
在路由中注册过滤器
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.RouterFunctions; import org.springframework.web.reactive.function.server.ServerResponse; @Configuration public class ApiRouterConfig { @Bean public RouterFunction<ServerResponse> apiRoutes(YourRequestHandler handler) { return RouterFunctions.route() // 配置你的API路由 .GET("/api/resources", handler::getAllResources) .POST("/api/resources", handler::createResource) // 注册自定义过滤器 .filter(CustomHeaderFilter.addCustomResponseHeader()) .build(); } }
方案2:处理大文件/二进制响应
如果你的接口返回大文件或二进制数据,使用bodyToMono(String.class)可能会导致内存溢出,这时候可以用DataBuffer来流式处理:
import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBufferUtils; import org.springframework.web.reactive.function.server.ExchangeFilterFunction; import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; public class CustomHeaderFilter { public static ExchangeFilterFunction addCustomResponseHeaderForBinary() { return ExchangeFilterFunction.ofResponseProcessor(originalResponse -> { // 以Flux形式读取原始响应体的DataBuffer return originalResponse.bodyToFlux(DataBuffer.class) .collectList() .flatMap(dataBuffers -> { // 合并所有DataBuffer(避免多次IO) DataBuffer combinedBuffer = originalResponse.exchange().bufferFactory().join(dataBuffers); // 保留DataBuffer引用,防止被提前释放导致内存泄漏 DataBufferUtils.retain(combinedBuffer); // 构建新响应 return ServerResponse.status(originalResponse.statusCode()) .headers(headers -> { headers.addAll(originalResponse.headers().asHttpHeaders()); headers.add("X-Custom-Header", "Binary-Response-Value"); }) .bodyValue(Flux.just(combinedBuffer)); }); }); } }
注意事项
- Spring Boot 2.0.1对应Spring WebFlux 5.0.x,上述API均兼容该版本;
- 如果你的响应体是特定类型(如自定义DTO),只需将
bodyToMono(String.class)替换为bodyToMono(YourDto.class)即可; - 处理二进制响应时,务必通过
DataBufferUtils.retain()保留缓冲区引用,避免出现IllegalStateException。
内容的提问来源于stack exchange,提问作者Niranjan
相关产品推荐
相关产品推荐

