Spring Cloud Gateway自定义过滤器:请求体转请求头后控制器丢失请求体
问题分析与解决方案
问题根源
- WebFlux中请求体是一次性消费的
Flux<DataBuffer>,读取原请求体后若不重新生成请求体数据,后续链路(如控制器)将无法获取请求体 - 原代码仅尝试修改请求头,但未将读取到的请求体重新封装回新请求中,导致后续请求体丢失
- 直接释放原
DataBuffer后,没有为后续流程提供可读取的请求体数据源
修正后的代码
@Component @Slf4j public class GetFormGatewayFilterFactory extends AbstractGatewayFilterFactory<GetFormGatewayFilterFactory.Config> { public GetFormGatewayFilterFactory() { super(Config.class); } @Override public GatewayFilter apply(Config config) { return (exchange, chain) -> { return DataBufferUtils.join(exchange.getRequest().getBody()) .flatMap(dataBuffer -> { // 读取请求体字节数组 byte[] bytes = new byte[dataBuffer.readableByteCount()]; dataBuffer.read(bytes); // 释放原DataBuffer资源 DataBufferUtils.release(dataBuffer); String body = new String(bytes, StandardCharsets.UTF_8); log.debug("读取到请求体内容: {}", body); // 基于原请求体字节重新创建DataBuffer,供后续链路读取 DataBuffer newDataBuffer = exchange.getResponse().bufferFactory().wrap(bytes); // 保留buffer引用,防止被提前释放 DataBufferUtils.retain(newDataBuffer); // 构建新请求:添加自定义请求头,同时替换请求体为重新生成的DataBuffer ServerHttpRequest newRequest = exchange.getRequest().mutate() .header("headerName", body) .body(Mono.just(newDataBuffer)) .build(); // 使用新的Exchange继续执行网关链路 return chain.filter(exchange.mutate().request(newRequest).build()); }) // 处理请求体为空的场景,避免链路中断 .switchIfEmpty(chain.filter(exchange)); }; } public static class Config { // 可在此添加过滤器配置属性 } }
关键说明
- 重新生成请求体:读取原请求体后,必须通过
bufferFactory().wrap(bytes)创建新的DataBuffer,并将其设置为新请求的body,确保后续链路能读取到请求体 - 资源管理:使用
DataBufferUtils.retain保证新创建的DataBuffer不会被提前释放,避免后续读取时出现资源已释放的错误 - 空请求体处理:通过
switchIfEmpty处理请求体为空的情况,确保链路能正常执行 - 请求头设置:在新请求中添加自定义请求头,确保后续链路能获取到该头部信息
内容的提问来源于stack exchange,提问作者노민영
相关产品推荐
相关产品推荐

