如何在Spring Cloud Gateway过滤器中将WebClient响应转为ServerHttpResponse?
Spring Cloud Gateway过滤器中用WebClient转发响应的实现方案
核心实现思路
当请求头包含Test时,通过WebClient调用目标服务,将目标服务的响应(状态码、响应头、响应体)直接作为网关的响应返回,不再继续执行后续过滤器链。
完整代码实现
import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.client.reactive.ClientHttpResponse; import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; @Component public class CustomForwardFilter implements GatewayFilter { private final WebClient webClient; // 推荐通过构造注入WebClient,避免每次创建新实例 public CustomForwardFilter(WebClient.Builder webClientBuilder) { this.webClient = webClientBuilder.build(); } @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { if (exchange.getRequest().getHeaders().containsKey("Test")) { ServerHttpResponse response = exchange.getResponse(); String targetUrl = "http://localhost:8080/test"; return webClient.get() .uri(targetUrl) .exchangeToMono(clientResponse -> { // 复制目标服务的响应状态码 response.setStatusCode(clientResponse.statusCode()); // 复制目标服务的响应头(排除Transfer-Encoding等网关会处理的头) HttpHeaders targetHeaders = clientResponse.headers().asHttpHeaders(); response.getHeaders().putAll(targetHeaders); // 写入响应体到网关响应 return response.writeWith(clientResponse.bodyToFlux(byte[].class)); }); } // 不满足条件时继续执行过滤器链 return chain.filter(exchange); } }
关键细节说明
- WebClient实例管理:不要每次调用都用
WebClient.create()创建新实例,推荐通过WebClient.Builder注入,实现复用和统一配置。 - 响应头处理:复制目标服务的响应头时,网关会自动处理
Transfer-Encoding、Content-Length等头,无需手动干预。 - 响应体写入:使用
bodyToFlux(byte[].class)将目标服务的响应体转为Flux,再通过response.writeWith()写入到网关响应中,保证响应体完整传输。 - 异常处理(可选):如果需要处理目标服务调用失败的情况,可以添加
onErrorResume逻辑,比如返回自定义错误响应:.onErrorResume(e -> { response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR); response.getHeaders().setContentType(MediaType.TEXT_PLAIN); String errorMsg = "调用目标服务失败: " + e.getMessage(); return response.writeWith(Mono.just(response.bufferFactory().wrap(errorMsg.getBytes()))); })
内容的提问来源于stack exchange,提问作者LucyEly
相关产品推荐
相关产品推荐

