使用GateWay整合Nacos及路由断言工厂的使用

754 阅读7分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第11天,点击查看活动详情

  1. 一、整合作用

在上篇文章主要介绍了GateWay的相关功能、以及一个简单通过GateWay来进行转发的功能,在application.yml中配置相关转发规则,但是可以发现在转发服务的时候,使用的是http的访问路径,在前面的文章中也有提到,如果微服务使用http进行服务访问,那后期的维护成本是非常高的,因此就需要通过整合Nacos来进行服务的处理。

image.png

二、集成Nacos

2-1、添加Nacos的依赖

<!-- nacos服务注册与发现 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

2-2、配置application.yml文件

首先配置了Nacos的连接地址,如果开启了鉴权,需要配置用户名密码;
其次配置路由的URI,通过设置lb://来设置使用Nacos的负载均衡策略,然后执行调用的服务名 image.png

2-3、重启GateWay服务、测试

如下可以看到GateWay服务和订单服务都已经注册到了Nacos中 image.png

访问测试:

image.png

2-4、application.yml的简写配置

上面在application.yml中的配置需要配置路由、断言以及过滤器,实际上还可以简写简略配置,如下:

image.png

通过设置locator.enabled:true,就可以让GateWay去自动识别Nacos中的服务

2-4-1、测试

如下,通过让GateWay去自动识别服务名,就可以自动去Nacos中找到服务对应的接口,进行访问,不需要再进行配置路由、断言、过滤器 image.png

一般情况下会选择使用路由、断言、过滤器的方式进行配置,因为代码配置的更加灵活,并且更加易于阅读。

三、路由断言工厂(Route Predicate Factories)配置

3-1、内置的断言工厂

作用: 当请求gateway的时候, 使用断言对请求进行匹配, 如果匹配成功就路由转发, 如果匹配失败就返回404

类型:内置,自定义

断言工厂可以去官网进行查看:docs.spring.io/spring-clou…

SpringCloud Gateway包括许多内置的断言工厂,所有这些断言都与HTTP请求的不同属性匹配。具体如下

3-1-1、基于Datetime类型的断言工厂

此类型的断言根据时间做判断,主要有三个:

AfterRoutePredicateFactory: 接收一个日期参数,判断请求日期是否晚于指定日期

BeforeRoutePredicateFactory: 接收一个日期参数,判断请求日期是否早于指定日期

BetweenRoutePredicateFactory: 接收两个日期参数,判断请求日期是否在指定时间段内

设置匹配时间必须是带区域的时间

获取时间可以通过:ZonedDateTime.now()来获取当前时间

3-1-1-1、基于before的断言工厂

通过以下配置,就可以设置只有在2022-07-20T17:42:47.789-07:00[Asia/Shanghai]之前的时间才能进行访问

spring:
  cloud:
    gateway:
      routes:
      - id: before_route
        uri: https://example.org
        predicates:
        - Before=2022-07-20T17:42:47.789-07:00[Asia/Shanghai]

3-1-1-2、基于After的断言工厂

通过以下配置,就可以设置只有在2022-07-20T17:42:47.789-07:00[Asia/Shanghai]之后的时间才能进行访问

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - After=2022-07-20T17:42:47.789-07:00[Asia/Shanghai]

3-1-1-3、基于Between的断言工厂

通过以下配置,就可以设置只有在2022-07-20T17:42:47.789-07:00[Asia/Shanghai]和2022-09-20T17:42:47.789-07:00[Asia/Shanghai]之间的时间才能进行访问

spring:
  cloud:
    gateway:
      routes:
      - id: between_route
        uri: https://example.org
        predicates:
        - Between=2022-07-20T17:42:47.789-07:00[Asia/Shanghai], 2022-09-20T17:42:47.789-07:00[Asia/Shanghai]

3-1-2、基于Cookie的断言工厂

通过以下配置,就可以设置只有当cookie中chocolate的值为ch.p的时候才能进行访问,另外值支持正则表达式

spring:
  cloud:
    gateway:
      routes:
      - id: cookie_route
        uri: https://example.org
        predicates:
        - Cookie=chocolate,ch.p

3-1-3、基于Header的断言工厂

通过以下配置,就可以设置请求头的断言工厂,需要请求投中有X-Request-Id,并且值为xxxxb时可以访问,另外值支持正则表达式

spring:
  cloud:
    gateway:
      routes:
      - id: header_route
        uri: https://example.org
        predicates:
        - Header=X-Request-Id,xxxxb

3-1-4、基于Host的断言工厂

通过以下配置就可以设置Host的断言工厂,支持通配符以及多个Host,多个Host之间用“,”隔开

spring:
  cloud:
    gateway:
      routes:
      - id: host_route
        uri: https://example.org
        predicates:
        - Host=**.somehost.org,**.anotherhost.org

3-1-5、基于Method请求方法的断言工厂

可以设置请求的Method,如下:

spring:
  cloud:
    gateway:
      routes:
      - id: method_route
        uri: https://example.org
        predicates:
        - Method=GET,POST

3-1-6、基于Path请求路径的断言工厂

通过路径进行设置断言,路径中支持*号通配符,同时也支持占位符,比如请求路径为/user/123,那么就可以设置- Path=/user/{id}

spring:
  cloud:
    gateway:
      routes:
      - id: path_route
        uri: https://example.org
        predicates:
        - Path=/red/{segment},/blue/{segment}

3-1-7、基于Query请求参数的断言工厂

通过设置请求Query来设置断言工厂,以下配置就是在Query参数中必须有green参数,参数支持正则表达式设置,如果要给参数设置值可以进行如下配置:

- Query=name,zhangsan|lisi
上面配置的含义为:Query中必须有name参数,值是zhangsan或者李四

spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: https://example.org
        predicates:
        - Query=green

3-1-8、基于远程地址的断言工厂

其中192.168.1.1是 IP 地址和24子网掩码,可以可以直接配置ip地址

spring:
  cloud:
    gateway:
      routes:
      - id: remoteaddr_route
        uri: https://example.org
        predicates:
        - RemoteAddr=192.168.1.1/24

3-1-9、基于路由权重的断言工厂

当前配置有两个路由规则,其中一个权重是8,另外一个是2,假设当10个请求进来的时候,就会有8个访问第一个,2个访问第二个;另外要配置权重的话使用Weight,值第一个为分组,第二个为权重值,这样下面两个都设置group1,就是这两个为一个分组。

spring:
  cloud:
    gateway:
      routes:
      - id: weight_high
        uri: https://weighthigh.org
        predicates:
        - Weight=group1, 8
      - id: weight_low
        uri: https://weightlow.org
        predicates:
        - Weight=group1, 2

3-2、自定义断言工厂

3-2-1、自定义断言的核心步骤

自定义路由断言工厂需要继承 AbstractRoutePredicateFactory 类,重写 apply 方法的逻辑。在 apply 方法中可以通过 exchange.getRequest() 拿到 ServerHttpRequest 对象,从而可以获取到请求的参数、请求方式、请求头等信息。

下面就以Query这个断言工厂来看下,断言工厂都需要哪些相关代码内容 image.png

1、 必须spring组件 bean

2、类必须加上RoutePredicateFactory作为结尾,比如自定一个自己的断言工厂,名称为:MyPreRoutePredicateFactory;MyPre为自己定义内容,RoutePredicateFactory为必须添加的名称

3、必须继承AbstractRoutePredicateFactory,可以看到内置的这些断言工厂都继承了这个类 image.png

4、必须声明静态内部类 声明属性来接收 配置文件中对应的断言的信息

image.png

5、需要结合shortcutFieldOrder进行绑定 这样在配置文件中的 Query=name,zhangsan。就可以将name映射到PARAM_KEY,将zhangsan映射到REGEXP_KEY上面。 image.png

6、通过apply进行逻辑判断 true就是匹配成功 false匹配失败

image.png

3-2-2、创建自定义断言工厂

为了方便演示、仅做一个简单的断言工厂,目标是当application.yml中配置了自定义断言工厂的时候,传入的值必须是jony才运行通过。

3-2-2-1、创建自定义断言工厂

最简单的方式就是,拷贝一个内置的自定义断言工厂,然后再进行修改即可。

下面配置了获取值为test的时候才进行放行。

JonyRoutePredicateFactory.java

package com.jony.predicate;

import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.GatewayPredicate;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;

import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;

@Component
public class JonyRoutePredicateFactory extends AbstractRoutePredicateFactory<JonyRoutePredicateFactory.Config> {

    public JonyRoutePredicateFactory() {
        super(Config.class);
    }

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return new GatewayPredicate() {

            @Override
            public boolean test(ServerWebExchange serverWebExchange) {
                if(config.getName().equals("test")){
                    return true;
                }
                return false;
            }
        };
    }

    /**
     * 快捷配置
     * @return
     */
    @Override
    public List<String> shortcutFieldOrder() {
        return Collections.singletonList("name");
    }

    public static class Config {

        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}

3-2-2-2、配置application.yml

server:
  port: 8088
spring:
  application:
    name: api-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.253.131:8851
        username: nacos
        password: nacos
    gateway:
      routes:
        - id: seata-order
          uri: lb://seata-order
          predicates:
            - Jony=test

3-2-2-3、测试

image.png

修改配置文件,这样就和自定义断言中的值不一样了。

image.png

再次访问如下: image.png