A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

1. 概述
本文主要分享 WebClientHttpRoutingFilter 的代码实现。
WebClientHttpRoutingFilter ,Http 路由网关过滤器。其根据 http:// 或 https:// 前缀( Scheme )过滤处理,使用基于 org.springframework.cloud.gateway.filter.WebClient 实现的 HttpClient 请求后端 Http 服务。
WebClientWriteResponseFilter ,与 WebClientHttpRoutingFilter 成对使用的网关过滤器。其将 WebClientWriteResponseFilter 请求后端 Http 服务的响应写回客户端。
大体流程如下 :

推荐 Spring Cloud 书籍:
推荐 Spring Cloud 视频:
2. 环境配置
目前 WebClientHttpRoutingFilter / WebClientWriteResponseFilter 处于实验阶段,建议等正式发布在使用。
OK,下面我们来看看怎么配置环境。
第一步,在 NettyConfiguration 注释掉 #routingFilter(...) 和 #nettyWriteResponseFilter()两个 Bean 方法。
第二步,在 GatewayAutoConfiguration 打开 #webClientHttpRoutingFilter() 和#webClientWriteResponseFilter() 两个 Bean 方法。
第三步,配置完成,启动 Spring Cloud Gateway 。
3. WebClientHttpRoutingFilter
org.springframework.cloud.gateway.filter.WebClientHttpRoutingFilter ,Http 路由网关过滤器。
构造方法,代码如下 :
public class WebClientHttpRoutingFilter implements GlobalFilter, Ordered {        private final WebClient webClient;        public WebClientHttpRoutingFilter(WebClient webClient) {                this.webClient = webClient;        }}
  • webClient 属性,默认情况下,使用org.springframework.web.reactive.function.client.DefaultWebClient 实现类。通过该属性,请求后端的 Http 服务。

#getOrder() 方法,代码如下 :
@Overridepublic int getOrder() {    return Ordered.LOWEST_PRECEDENCE;}
#filter(ServerWebExchange, GatewayFilterChain) 方法,代码如下 :
1: @Override 2: public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { 3:         // 获得 requestUrl 4:         URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR); 5:  6:         // 判断是否能够处理 7:         String scheme = requestUrl.getScheme(); 8:         if (isAlreadyRouted(exchange) || (!scheme.equals("http") && !scheme.equals("https"))) { 9:                 return chain.filter(exchange);10:         }11: 12:         // 设置已经路由13:         setAlreadyRouted(exchange);14: 15:         ServerHttpRequest request = exchange.getRequest();16: 17:         //TODO: support forms18:         // Request Method19:         HttpMethod method = request.getMethod();20: 21:         // Request22:         RequestBodySpec bodySpec = this.webClient.method(method)23:                         .uri(requestUrl)24:                         .headers(httpHeaders -> {25:                                 httpHeaders.addAll(request.getHeaders());26:                                 httpHeaders.remove(HttpHeaders.HOST);27:                         });28: 29:         // Request Body30:         RequestHeadersSpec<?> headersSpec;31:         if (requiresBody(method)) {32:                 headersSpec = bodySpec.body(BodyInserters.fromDataBuffers(request.getBody()));33:         } else {34:                 headersSpec = bodySpec;35:         }36: 37:         return headersSpec.exchange()38:                         // .log("webClient route")39:                         .flatMap(res -> {40:                                 ServerHttpResponse response = exchange.getResponse();41: 42:                                 // Response Header43:                                 response.getHeaders().putAll(res.headers().asHttpHeaders());44: 45:                                 // Response Status46:                                 response.setStatusCode(res.statusCode());47: 48:                                 // 设置 Response 到 CLIENT_RESPONSE_ATTR49:                                 // Defer committing the response until all route filters have run50:                                 // Put client response as ServerWebExchange attribute and write response later NettyWriteResponseFilter51:                                 exchange.getAttributes().put(CLIENT_RESPONSE_ATTR, res);52:                                 return chain.filter(exchange);53:                         });54: }
  • 第 4 行 :获得 requestUrl 。
  • 第 7 至 10 行 :判断 ForwardRoutingFilter 是否能够处理该请求,需要满足两个条件 :
    • http:// 或者 https:// 前缀( Scheme ) 。
    • 调用 ServerWebExchangeUtils#isAlreadyRouted(ServerWebExchange) 方法,判断该请求暂未被其他 Routing 网关处理。代码如下 :
      public static boolean isAlreadyRouted(ServerWebExchange exchange) {    return exchange.getAttributeOrDefault(GATEWAY_ALREADY_ROUTED_ATTR, false);}
      • x

  • 第 13 行 :设置该请求已经被处理。代码如下 :
    public static void setAlreadyRouted(ServerWebExchange exchange) {    exchange.getAttributes().put(GATEWAY_ALREADY_ROUTED_ATTR, true);}
  • 第 17 行 :TODO 【3025】 目前暂不支持 forms 参数
  • 第 22 至 35 行 :创建向后端服务的请求。
    • 第 22 行 :设置 Method 属性。
    • 第 24 至 27 行 :设置 Header 属性。
    • 第 30 至 35 行 :设置 Body 属性。
  • 第 37 行 :发起向后端服务的请求。
  • 第 40 至 53 行 :处理返回自后端服务的相应。
    • 第 43 行 :设置 response 的 Header 属性。
    • 第 46 行 :设置 response 的 Status 属性。
    • 第 51 行 :设置 res 到 CLIENT_RESPONSE_ATTR 。后续 WebClientWriteResponseFilter 将响应写回给客户端。
    • 第 52 行 :提交过滤器链继续过滤。

4. WebClientWriteResponseFilter
org.springframework.cloud.gateway.filter.WebClientWriteResponseFilter ,Http 回写响应网关过滤器。
#getOrder() 方法,代码如下 :
public static final int WRITE_RESPONSE_FILTER_ORDER = -1;    @Overridepublic int getOrder() {    return WRITE_RESPONSE_FILTER_ORDER;}
#filter(ServerWebExchange, GatewayFilterChain) 方法,代码如下 :
1: @Override 2: public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { 3:         // NOTICE: nothing in "pre" filter stage as CLIENT_RESPONSE_ATTR is not added 4:         // until the WebHandler is run 5:         return chain.filter(exchange).then(Mono.defer(() -> { 6:             // 获得 Response 7:                 ClientResponse clientResponse = exchange.getAttribute(CLIENT_RESPONSE_ATTR); 8:                 if (clientResponse == null) { 9:                         return Mono.empty();10:                 }11:                 log.trace("WebClientWriteResponseFilter start");12:                 ServerHttpResponse response = exchange.getResponse();13: 14:                 return response.writeWith(clientResponse.body(BodyExtractors.toDataBuffers())).log("webClient response");15:         }));16: }
  • 第 5 行 :调用 #then(Mono) 方法,实现 After Filter 逻辑。
  • 第 7 至 11 行 :从 CLIENT_RESPONSE_ATTR 中,获得 ClientResponse 。
  • 第 14 行 :将 ClientResponse 写回给客户端。
5. 和 NettyRoutingFilter 对比
《Spring-Cloud-Gateway 源码解析 —— 过滤器 (4.7) 之 NettyRoutingFilter》 中,我们知道 NettyRoutingFilter / NettyWriteResponseFilter 和 WebClientHttpRoutingFilter / WebClientHttpRoutingFilter 实现一样的功能。

6 个回复

倒序浏览
优秀,奈斯
回复 使用道具 举报
回复 使用道具 举报
回复 使用道具 举报
回复 使用道具 举报
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马