网关 Spring-Cloud-Gateway 源码解析 —— 过滤器 (4.8) 之 WebClientHttpRoutingFilter

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】
免费领取10G资料包与项目实战视频资料

摘要: 原创出处 http://www.iocoder.cn/Spring-Cloud-Gateway/filter-web-client-http-routing/ 「芋道源码」欢迎转载,保留摘要,谢谢!

本文主要基于 Spring-Cloud-Gateway 2.0.X M4

20191123100319\_1.png

������关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右

> 5. 认真的源码交流微信群。

1. 概述

本文主要分享 WebClientHttpRoutingFilter 的代码实现

WebClientHttpRoutingFilter ,Http 路由网关过滤器。其根据 http://https:// 前缀( Scheme )过滤处理,使用基于 org.springframework.cloud.gateway.filter.WebClient 实现的 HttpClient 请求后端 Http 服务。

WebClientWriteResponseFilter ,与 WebClientHttpRoutingFilter 成对使用的网关过滤器。其将 WebClientWriteResponseFilter 请求后端 Http 服务的响应写回客户端。

大体流程如下 :

20191123100319\_2.png

推荐 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() 方法,代码如下 :

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }
  • 返回顺序为 MARKDOWN_HASHe7a95d949116a2da0f0fa83dc6e76c00MARKDOWNHASH 。在 [《Spring-Cloud-Gateway 源码解析 —— 过滤器 (4.1) 之 GatewayFilter 一览》「3. GlobalFilter」][Spring-Cloud-Gateway 4.1 _ GatewayFilter _3. GlobalFilter] ,我们列举了所有 GlobalFilter 的顺序。

#filter(ServerWebExchange, GatewayFilterChain) 方法,代码如下 :

      1: @Override
      2: public Mono 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 forms
     18:  // Request Method
     19:  HttpMethod method = request.getMethod();
     20: 
     21:  // Request
     22:  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 Body
     30:  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 Header
     43:  response.getHeaders().putAll(res.headers().asHttpHeaders());
     44: 
     45:  // Response Status
     46:  response.setStatusCode(res.statusCode());
     47: 
     48:  // 设置 Response 到 CLIENT_RESPONSE_ATTR
     49:  // Defer committing the response until all route filters have run
     50:  // Put client response as ServerWebExchange attribute and write response later NettyWriteResponseFilter
     51:  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 行 :设置 resCLIENT_RESPONSE_ATTR 。后续 WebClientWriteResponseFilter 将响应写回给客户端。
    • 第 52 行 :提交过滤器链继续过滤。

4. WebClientWriteResponseFilter

org.springframework.cloud.gateway.filter.WebClientWriteResponseFilter ,Http 回写响应网关过滤器。

#getOrder() 方法,代码如下 :

    public static final int WRITE_RESPONSE_FILTER_ORDER = -1;

    @Override
    public int getOrder() {
        return WRITE_RESPONSE_FILTER_ORDER;
    }
  • 返回顺序为 MARKDOWN_HASH6bb61e3b7bce0931da574d19d1d82c88MARKDOWNHASH 。在 [《Spring-Cloud-Gateway 源码解析 —— 过滤器 (4.1) 之 GatewayFilter 一览》「3. GlobalFilter」][Spring-Cloud-Gateway 4.1 _ GatewayFilter _3. GlobalFilter] ,我们列举了所有 GlobalFilter 的顺序。

#filter(ServerWebExchange, GatewayFilterChain) 方法,代码如下 :

      1: @Override
      2: public Mono 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 实现一样的功能。

那么为什么要再实现一次呢?

TODO 【3001】

666. 彩蛋

20191123100319\_3.png

呼呼,主要的过滤器已经写完,后面熔断、限流过滤器的实现。

20191123100319\_4.png

胖友,分享一波朋友圈可好!

20191123100319\_5.png

������关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

来源:http://ddrv.cn/a/88268

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » 网关 Spring-Cloud-Gateway 源码解析 —— 过滤器 (4.8) 之 WebClientHttpRoutingFilter

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏