看啥推荐读物
公众号:芋道源码
今天看啥  ›  专栏  ›  芋道源码_以德服人_不服就干

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

芋道源码_以德服人_不服就干  · 掘金  · 数据库  · 2019-05-04 22:00
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 www.iocoder.cn/Spring-Clou… 「芋道源码」欢迎转载,保留摘要,谢谢!

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


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

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

1. 概述

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

RouteToRequestUrlFilter ,转发路由网关过滤器。其根据 forward:// 前缀( Scheme )过滤处理,将请求转发到当前网关实例本地接口

举个例子,配置 RouteDefinition 路由定义如下 :

spring:
  application:
      name: juejin-gateway
  cloud:
    gateway:
      routes:
      # =====================================
      - id: forward_sample
        uri: forward:///globalfilters
        order: 10000
        predicates:
        - Path=/globalfilters
        filters:
        - PrefixPath=/application/gateway
  • 我们假定网关端口为 8080
  • 当请求 http://127.0.0.1:8080/globalfilters 接口,Spring Cloud Gateway 处理过程如下 :
    • 匹配到路由 Route (id = forward_sample) 。
    • 配置的 PrefixPathGatewayFilterFactory 将请求改写http://127.0.0.1:8080/application/gateway/globalfilters
    • ForwardRoutingFilter 判断有 forward:// 前缀( Scheme ),过滤处理,将请求转发给 DispatcherHandler 。
    • DispatcherHandler 匹配并转发到当前网关实例本地接口 application/gateway/globalfilters
  • 为什么需要配置 PrefixPathGatewayFilterFactory ?需要通过 PrefixPathGatewayFilterFactory 将请求重写路径,以匹配本地 API ,否则 DispatcherHandler 转发会失败。

另外,RouteToRequestUrlFilter 是 Spring Cloud Gateway 实现的一种路由网关过滤器,目前还提供 WebsocketRoutingFilter / NettyRoutingFilter / WebClientHttpRoutingFilter 。


推荐 Spring Cloud 书籍

2. RouteToRequestUrlFilter

org.springframework.cloud.gateway.filter.ForwardRoutingFilter ,代码如下 :

 1: public class ForwardRoutingFilter implements GlobalFilter, Ordered {
 2: 
 3: 	private static final Log log = LogFactory.getLog(ForwardRoutingFilter.class);
 4: 
 5: 	private final DispatcherHandler dispatcherHandler;
 6: 
 7: 	public ForwardRoutingFilter(DispatcherHandler dispatcherHandler) {
 8: 		this.dispatcherHandler = dispatcherHandler;
 9: 	}
10: 
11: 	@Override
12: 	public int getOrder() {
13: 		return Ordered.LOWEST_PRECEDENCE;
14: 	}
15: 
16: 	@Override
17: 	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
18: 	    // 获得 requestUrl
19: 		URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);
20: 
21: 		// 判断是否能够处理
22: 		String scheme = requestUrl.getScheme();
23: 		if (isAlreadyRouted(exchange) || !scheme.equals("forward")) {
24: 			return chain.filter(exchange);
25: 		}
26: 
27: 		// 设置已经路由
28: 		setAlreadyRouted(exchange);
29: 
30: 		//TODO: translate url?
31: 
32: 		if (log.isTraceEnabled()) {
33: 			log.trace("Forwarding to URI: "+requestUrl);
34: 		}
35: 
36: 		// DispatcherHandler 匹配并转发到当前网关实例本地接口
37: 		return this.dispatcherHandler.handle(exchange);
38: 	}
39: }
  • 实现 GlobalFilter 接口。
  • #getOrder() 方法,返回顺序为 Integer.MAX_VALUE 。在 《Spring-Cloud-Gateway 源码解析 —— 过滤器 (4.1) 之 GatewayFilter 一览》「3. GlobalFilter」 ,我们列举了所有 GlobalFilter 的顺序。
  • 第 19 行 :获得 requestUrl
  • 第 22 至 25 行 :判断 ForwardRoutingFilter 是否能够处理该请求,需要满足两个条件 :

    • forward:// 前缀( Scheme ) 。
    • 调用 ServerWebExchangeUtils#isAlreadyRouted(ServerWebExchange) 方法,判断该请求暂未被其他 Routing 网关处理。代码如下 :

      public static boolean isAlreadyRouted(ServerWebExchange exchange) {
          return exchange.getAttributeOrDefault(GATEWAY_ALREADY_ROUTED_ATTR, false);
      }
      
      • x
  • 第 28 行 :设置该请求已经被处理。代码如下 :

    public static void setAlreadyRouted(ServerWebExchange exchange) {
        exchange.getAttributes().put(GATEWAY_ALREADY_ROUTED_ATTR, true);
    }
    
  • 第 37 行 :将请求转发给 DispatcherHandler 。DispatcherHandler 匹配并转发到当前网关实例本地接口

666. 彩蛋

知识星球

一开始想错了 ForwardRoutingFilter 了的用途,调试许久,后面看了官方提供的示例 org.springframework.cloud.gateway.test.ForwardTests ,豁然开朗。

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




原文地址:访问原文地址
快照地址: 访问文章快照