Spring Cloud Alibaba - 25 Gateway-路由断言工厂Route Predicate Factories谓词工厂示例及源码解析

Posted 小小工匠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Cloud Alibaba - 25 Gateway-路由断言工厂Route Predicate Factories谓词工厂示例及源码解析相关的知识,希望对你有一定的参考价值。

文章目录


官网

https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-request-predicates-factories

Spring Cloud Gateway 将路由匹配为 Spring WebFluxHandlerMapping基础架构的一部分。Spring Cloud Gateway 包含许多内置的路由谓词工厂。所有这些谓词都匹配 HTTP 请求的不同属性。我们可以将多个路由谓词工厂与逻辑and语句结合起来。


The After Route Predicate Factory

https://cloud.spring.io/spring-cloud-gateway/reference/html/#the-after-route-predicate-factory

小栗子

我们还是继续老工程 ,启动

artisan-cloud-gateway 【8888】

artisan-cloud-gateway-order

artisan-cloud-gateway-product


【网关配置】

application-after_route.yml

#  网关的After谓词,对应的源码处理AfterRoutePredicateFactory
#作用: 经过网关的所有请求 当前时间>比After阈值  就进行转发
#现在我们是2022年了 currentTime<After阈值,所以网关不会进行转发,而返回404spring:
spring:
  cloud:
    gateway: #gateway
      routes:
        - id: after_route  # id 确保唯一
          uri: lb://artisan-cloud-gateway-order  #  nacos上的 注册地址
          predicates:
            - After=2025-02-13T18:27:28.309+08:00[Asia/Shanghai]

currentTime<After阈值,所以网关不会进行转发 .

激活配置文件

【测试】

符合预期。

如果我们改下时间呢?

AfterRoutePredicateFactory源码

public class AfterRoutePredicateFactory
		extends AbstractRoutePredicateFactory<AfterRoutePredicateFactory.Config> 

	/**
	 * DateTime key.
	 */
	public static final String DATETIME_KEY = "datetime";

	public AfterRoutePredicateFactory() 
		super(Config.class);
	

	@Override
	public List<String> shortcutFieldOrder() 
		return Collections.singletonList(DATETIME_KEY);
	

	@Override
	public Predicate<ServerWebExchange> apply(Config config) 
		return new GatewayPredicate() 
			@Override
			public boolean test(ServerWebExchange serverWebExchange) 
				final ZonedDateTime now = ZonedDateTime.now();
				return now.isAfter(config.getDatetime());
			

			@Override
			public String toString() 
				return String.format("After: %s", config.getDatetime());
			
		;
	

	public static class Config 

		@NotNull
		private ZonedDateTime datetime;

		public ZonedDateTime getDatetime() 
			return datetime;
		

		public void setDatetime(ZonedDateTime datetime) 
			this.datetime = datetime;
		

	


核心方法,apply,比较简单。


The Before Route Predicate Factory

https://cloud.spring.io/spring-cloud-gateway/reference/html/#the-before-route-predicate-factory

小栗子

application-before_route.yml

#目的:测试网关的Before谓词,对应的源码处理BeforeRoutePredicateFactory
#作用: 经过网关的所有请求当前时间 比Before=2021-02-13T18:27:28.309+08:00[Asia/Shanghai] 小  就进行转发
#现在2022年了 时间比配置的阈值大,所以我们不会进行转发,而返回404
#2021-02-13T18:27:28.309+08:00[Asia/Shanghai] 这个时间怎么获取的呢? --- System.out.println(ZonedDateTime.now())
spring:
  cloud:
    gateway: #gateway
      routes:
        - id: before_route  # id 确保唯一
          uri: lb://artisan-cloud-gateway-order
          predicates:
            - Before=2023-02-13T18:27:28.309+08:00[Asia/Shanghai]

BeforeRoutePredicateFactory源码

public class BeforeRoutePredicateFactory
		extends AbstractRoutePredicateFactory<BeforeRoutePredicateFactory.Config> 

	/**
	 * DateTime key.
	 */
	public static final String DATETIME_KEY = "datetime";

	public BeforeRoutePredicateFactory() 
		super(Config.class);
	

	@Override
	public List<String> shortcutFieldOrder() 
		return Collections.singletonList(DATETIME_KEY);
	

	@Override
	public Predicate<ServerWebExchange> apply(Config config) 
		return new GatewayPredicate() 
			@Override
			public boolean test(ServerWebExchange serverWebExchange) 
				final ZonedDateTime now = ZonedDateTime.now();
				return now.isBefore(config.getDatetime());
			

			@Override
			public String toString() 
				return String.format("Before: %s", config.getDatetime());
			
		;
	

	public static class Config 

		private ZonedDateTime datetime;

		public ZonedDateTime getDatetime() 
			return datetime;
		

		public void setDatetime(ZonedDateTime datetime) 
			this.datetime = datetime;
		

	




The Between Route Predicate Factory

https://cloud.spring.io/spring-cloud-gateway/reference/html/#the-between-route-predicate-factory

小栗子

application-between-route.yml

# Between谓词  BetweenRoutePredicateFactory
# 就是经过网关请求的当前时间 currentTime 满足
# Between startTime < currentTime < Between EndTime 才进行转发
spring:
  cloud:
    gateway:
      routes:
        - id: between-route #id必须要唯一
          uri: lb://artisan-cloud-gateway-order  # 这里可以使用负载均衡的写法
          predicates:
            - Between=2020-02-13T18:27:28.309+08:00[Asia/Shanghai],2025-02-13T18:27:28.309+08:00[Asia/Shanghai]

BetweenRoutePredicateFactory源码

public class BetweenRoutePredicateFactory
		extends AbstractRoutePredicateFactory<BetweenRoutePredicateFactory.Config> 

	/**
	 * DateTime 1 key.
	 */
	public static final String DATETIME1_KEY = "datetime1";

	/**
	 * DateTime 2 key.
	 */
	public static final String DATETIME2_KEY = "datetime2";

	public BetweenRoutePredicateFactory() 
		super(Config.class);
	

	@Override
	public List<String> shortcutFieldOrder() 
		return Arrays.asList(DATETIME1_KEY, DATETIME2_KEY);
	

	@Override
	public Predicate<ServerWebExchange> apply(Config config) 
		Assert.isTrue(config.getDatetime1().isBefore(config.getDatetime2()),
				config.getDatetime1() + " must be before " + config.getDatetime2());

		return new GatewayPredicate() 
			@Override
			public boolean test(ServerWebExchange serverWebExchange) 
				final ZonedDateTime now = ZonedDateTime.now();
				return now.isAfter(config.getDatetime1())
						&& now.isBefore(config.getDatetime2());
			

			@Override
			public String toString() 
				return String.format("Between: %s and %s", config.getDatetime1(),
						config.getDatetime2());
			
		;
	

	@Validated
	public static class Config 

		@NotNull
		private ZonedDateTime datetime1;

		@NotNull
		private ZonedDateTime datetime2;

		public ZonedDateTime getDatetime1() 
			return datetime1;
		

		public Config setDatetime1(ZonedDateTime datetime1) 
			this.datetime1 = datetime1;
			return this;
		

		public ZonedDateTime getDatetime2() 
			return datetime2;
		

		public Config setDatetime2(ZonedDateTime datetime2) 
			this.datetime2 = datetime2;
			return this;
		

	




The Cookie Route Predicate Factory

https://cloud.spring.io/spring-cloud-gateway/reference/html/#the-cookie-route-predicate-factory

小栗子

application-cookie-route.yml

#谓词 Cookie 源码  CookieRoutePredicateFactory
#表示通过网关的请求 必须带入包含了Cookie name=Company value=Artisan
#才转发请求
spring:
  cloud:
    gateway:
      routes:
        - id: cookie-route #id必须要唯一
          uri: lb://artisan-cloud-gateway-order  # 这里可以使用负载均衡的写法
          predicates:
            #当我们的请求中包含了Cookie name=Company value=Artisan
            #才转发请求
            - Cookie=Company,Artisan

CookieRoutePredicateFactory源码

核心方法

@Override
	public Predicate<ServerWebExchange> apply(Config config) 
		return new GatewayPredicate() 
			@Override
			public boolean test(ServerWebExchange exchange) 
				List<HttpCookie> cookies = exchange.getRequest().getCookies()
						.get(config.name);
				if (cookies == null) 
					return false;
				
				for (HttpCookie cookie : cookies) 
					if (cookie.getValue().matches(config.regexp)) 
						return true;
					
				
				return false;
			

			@Override
			public String toString() 
				return String.format("Cookie: name=%s regexp=%s", config.name,
						config.regexp);
			
		;
	


The Header Route Predicate Factory

https://cloud.spring.io/spring-cloud-gateway/reference/html/#the-header-route-predicate-factory

小栗子

application-header-route.yml

#Header谓词   源码HeaderRoutePredicateFactory
#说明请求经过网关 必须带入
#header的k=X-Request-appId v=Artisan才会被转发
spring:
  cloud:
    gateway:
      routes:
        - id: header-route #id必须要唯一
          uri: lb://artisan-cloud-gateway-order
          predicates:
            - Header=X-Request-appId,Artisan

HeaderRoutePredicateFactory源码

@Override
	public Predicate<ServerWebExchange> apply(Config config) 
		boolean hasRegex = !StringUtils.isEmpty(config.regexp);

		return new GatewayPredicate() 
			@Override
			public boolean test(ServerWebExchange exchange) 
				List<String> values = exchange.getRequest().getHeaders()
						.getOrDefault(config.header, Collections.emptyList());
				if (values.isEmpty()) 
					return false;
				
				// values is now guaranteed to not be empty
				if (hasRegex) 
					// check if a header value matches
					return values.stream()
							.anyMatch(value -> value.matches(config.regexp));
				

				// there is a value and since regexp is empty, we only check existence.
				return true;
			

			@Override
			public String toString() 
				return String.format("Header: %s regexp=%s", config.header,
						config.regexp);
			
		;
	


The Host Route Predicate Factory

#Host谓词  源码HostRoutePredicateFactory 
#说明请求http://localhost:8888/selectOrderInfoById/1的
#Host必须满足www.artisan.com:8888或者localhost:8888才会
#转发到http://artisan-cloud-gateway-order/selectOrderInfoById/1

#而127.0.0.1不会被转发
spring:
  cloud:
    gateway:
      routes:
        - id: host-route #id必须要唯一
          uri: lb://artisan-cloud-gateway-order
          predicates:
            - Host=www.artisan.com:8888,localhost:8888


The Method Route Predicate Factory

#Http请求方法的谓词 Method 源码 MethodRoutePredicateFactory 
#表示经过网关的请求 只有post方式才能被转发
spring:
  cloud:
    gateway:
      routes:
       - id: method #id必须要唯一
         uri: lb://artisan-cloud-gateway-order
         predicates:
           #当前请求的方式 http://localhost:8888/selectOrderInfoById/1 是Post才会被转发
           #到http://artisan-cloud-gateway-order/selectOrderInfoById/1
           - Method=Post

The Path Route Predicate Factory


The Query Route Predicate Factory



The RemoteAddr Route Predicate Factory


The Weight Route Predicate Factory


源码

https://github.com/yangshangwei/SpringCloudAlibabMaster

以上是关于Spring Cloud Alibaba - 25 Gateway-路由断言工厂Route Predicate Factories谓词工厂示例及源码解析的主要内容,如果未能解决你的问题,请参考以下文章

Spring Cloud Alibaba全家桶——Spring Cloud Alibaba介绍

Spring Cloud Alibaba系列教程——Spring Cloud Alibaba开篇

给老板解释解释,为什么要用 Spring Cloud Alibaba 作为微服务开发框架?

spring boot 整合spring cloud alibaba

spring boot 整合spring cloud alibaba

深度剖析Spring Cloud Alibaba系列——如何兼容Spring Cloud