Spring Cloud Alibaba - Gateway 入门案例(三)(断言 / 过滤器)(自定义 断言 / (全局 / 局部)过滤器(非阿里组件))

Spring Cloud Alibaba - Gateway 入门案例(三)(断言 / 过滤器)(自定义 断言 / (全局 / 局部)过滤器)(非阿里组件)

回溯

在上一篇博客的 SpringCloud Gateway 讲解中 ,我们讲述到了,企业选择配置多的方式来使用 SpringCloud Gateway ,是因为这种方式比较灵活,之所以灵活,最最最主要,是体现在了两个参数上 断言(predicates)/ 过滤器(filters)

断言(predicates)

Spring Cloud Gateway matches routes as part of the Spring WebFlux HandlerMapping infrastructure. Spring Cloud Gateway includes many built-in route predicate factories. All of these predicates match on different attributes of the HTTP request. You can combine multiple route predicate factories with logical and statements.

Predicate(断言, 谓词) 用于进行条件判断,只有断言都返回真,才会真正的执行路由。

断言就是说: 在 什么条件下 才能进行路由转发

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

  • 基于Datetime类型的断言工厂,此类型的断言根据时间做判断,主要有三个:
    AfterRoutePredicateFactory: 接收一个日期参数,判断请求日期是否晚于指定日期
    BeforeRoutePredicateFactory: 接收一个日期参数,判断请求日期是否早于指定日期
    BetweenRoutePredicateFactory: 接收两个日期参数,判断请求日期是否在指定时间段内

例:Before=2020-07-09T00:00:00.000+08:00

  • 基于远程地址的断言工厂 RemoteAddrRoutePredicateFactory:接收一个IP地址段,判断请求主机地址是否在地址段中

例:-RemoteAddr=192.168.5.1/24

  • 基于Cookie的断言工厂
    CookieRoutePredicateFactory:接收两个参数,cookie 名字和一个正则表达式。 判断请求cookie是否具有给定名称且值与正则表达式匹配。

例:-Cookie=chocolate, ch.

  • 基于Header的断言工厂
    HeaderRoutePredicateFactory:接收两个参数,标题名称和正则表达式。 判断请求Header是否具有给定名称且值与正则表达式匹配。

例:-Header=X-Request-Id, \d+

  • 基于Host的断言工厂
    HostRoutePredicateFactory:接收一个参数,主机名模式。判断请求的Host是否满足匹配规则。

例:-Host=**.testhost.org

  • 基于Method请求方法的断言工厂
    MethodRoutePredicateFactory:接收一个参数,判断请求类型是否跟指定的类型匹配。

例:-Method=GET

  • 基于Path请求路径的断言工厂
    PathRoutePredicateFactory:接收一个参数,判断请求的URI部分是否满足路径规则。

例:-Path=/foo/{segment}

  • 基于Query请求参数的断言工厂
    QueryRoutePredicateFactory :接收两个参数,请求param和正则表达式, 判断请求参数是否具有给定名称且值与正则表达式匹配。

例:-Query=baz, ba.

这边附上文档地址,有需要可以去详细翻阅,博主的举例仅供参考。

在这里插入图片描述

点击 spring-cloud-gateway/2.2.3.RELEASE/reference/html/#gateway-request-predicates-factories 进入文档地址。

简单测试:配置文件如下

ps ( 此测试基于上一篇博文,若有疑问,请参考上一篇博文 )

server:
  port: 7777
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #让gateway可以发现nacos中的微服务
      routes: # 路由数组  指当请求满足什么样的条件的时候,转发到哪个微服务上
        - id: nacosxfz_route #当前路由标识,要求唯一 (默认值uuid,一般不用,需要自定义)
          uri: lb://test-scz #请求最终要被转发的地址   lb指的是从nacos中按照名称获取微服务,并遵循负载均衡策略
          order: 1 #路由优先级,数字越小,优先级越高
          predicates: #断言 判断条件,返回值是boolean 转发请求要返回的条件 (可以写多个)、
            - Path=/scz_server/** #当请求路径满足path指定的规则时,此路由信息才会正常转发
            - Method=POST
          filters: #过滤器(在请求传递过程中,对请求做一些手脚)
            - StripPrefix=1 # 在请求转发之前去掉一层路径
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

在这里插入图片描述
证明:当请求方法为Get的时候是无法成功地。

自定义断言

有很多情况下,这些断言并不能满足我们的业务需求,需要自定义断言。

比如,现在我希望参数中 name 带有 huge 或者 liuyifei 或者 pengyuyan 才能进行转发,那么就需要自定义断言。

首先需要在yam总添加自定义断言名称。

为了开发方便,添加插件

		<dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

在这里插入图片描述

然后添加一个配置类。

/**
 * 这是一个自定义的路由断言工厂类,要求有两个
 * 名字必须是 配置+RoutePredicateFactory  本类的配置字段是name
 * 必须继承 AbstractRoutePredicateFactory <配置类>
 */
@Component
public class NameRoutePredicateFactory extends AbstractRoutePredicateFactory <NameRoutePredicateFactory.Config>{
    
    

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

    /**
     * 读取配置文件的中参数值 给他赋值到配置类中的属性上
     * @return 配置类的数据
     */
    @Override
    public List<String> shortcutFieldOrder() {
    
    
        return Collections.singletonList("xianJian");
    }

    /**
     * 断言逻辑的具体内容
     * @param config 当前断言的配置读取
     * @return 断言结果
     */
    @Override
    public Predicate<ServerWebExchange> apply(NameRoutePredicateFactory.Config config) {
    
    
        return serverWebExchange -> {
    
    
            String name = serverWebExchange.getRequest().getQueryParams().getFirst("name");
            if(StringUtils.isNotBlank(name)){
    
    
                List<String> nameList = Arrays.asList(config.xianJian.split("\\|"));
                return nameList.contains(name);
            }
            return false;
        };
    }

    /**
     * 读取配置文件中的配置,按顺序配置参数
     */
    @Data
    @NoArgsConstructor
    public static class Config {
    
    
        private  String xianJian;
    }
}

ps: 这个类的名称 大有玄机 ,需要你自定义的属性名称 + RoutePredicateFactory 这个是固定用法

也可以参考:

在这里插入图片描述

这些类的编写,相信看过两个你就知道怎么自己编写了。

这时候进行测试,发现 name 带有 huge 或者 liuyifei 或者 pengyuyan 成功。
在这里插入图片描述

若条件不满足,无法转发,会报 404
在这里插入图片描述
在这里插入图片描述

过滤器(filters)

  • 作用: 过滤器就是在请求的传递过程中,对请求和响应做一些手脚
  • 生命周期: Pre Post
  • 分类: 局部过滤器(作用在某一个路由上) 全局过滤器(作用全部路由上)

在Gateway中, Filter的生命周期只有两个:“pre” 和 “post”。

  • PRE: 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
  • POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTPHeader、收集统计信息和指标、将响应从微服务发送给客户端等。

Gateway 的Filter从作用范围可分为两种: GatewayFilter与GlobalFilter。

  • GatewayFilter:应用到单个路由或者一个分组的路由上。
  • GlobalFilter:应用到所有的路由上。

局部过滤器

局部过滤器是针对单个路由的过滤器。

Route filters allow the modification of the incoming HTTP request or outgoing HTTP response in some manner. Route filters are scoped to a particular route. Spring Cloud Gateway includes many built-in GatewayFilter Factories.

在SpringCloud Gateway中内置了很多不同类型的网关路由过滤器。具体如下:

过滤器工厂 作用 参数
AddRequestHeader 为原始请求添加Header Header的名称及值
AddRequestParameter 为原始请求添加请求参数 参数名称及值
AddResponseHeader 为原始响应添加Header Header的名称及值
DedupeResponseHeader 剔除响应头中重复的值 需要去重的Header名称及去重策略
Hystrix 为路由引入Hystrix的断路器保护 HystrixCommand的名称
FallbackHeaders 为fallbackUri的请求头中添加具体的异常信息 Header的名称
PrefixPath 为原始请求路径添加前缀 前缀路径
PreserveHostHeader 为请求添加一个preserveHostHeader=true的属性,路由过滤器会检查该属性以决定是否要发送原始的Host
RequestRateLimiter 用于对请求限流,限流算法为令牌桶 keyResolver、rateLimiter、statusCode、denyEmptyKey、emptyKeyStatus
RedirectTo 将原始请求重定向到指定的URL http状态码及重定向的url
RemoveHopByHopHeadersFilter 为原始请求删除IETF组织规定的一系列Header 默认就会启用,可以通过配置指定仅删除哪些Header
RemoveRequestHeader 为原始请求删除某个Header Header名称
RemoveResponseHeader 为原始响应删除某个Header Header名称
RewritePath 重写原始的请求路径 原始路径正则表达式以及重写后路径的正则表达式
RewriteResponseHeader 重写原始响应中的某个Header Header名称,值的正则表达式,重写后的值
SaveSession 在转发请求之前,强制执行WebSession::save操作
secureHeaders 为原始响应添加一系列起安全作用的响应头 无,支持修改这些安全响应头的值
SetPath 修改原始的请求路径 修改后的路径
SetResponseHeader 修改原始响应中某个Header的值 Header名称,修改后的值
SetStatus 修改原始响应的状态码 HTTP 状态码,可以是数字,也可以是字符串
StripPrefix 用于截断原始请求的路径 使用数字表示要截断的路径的数量
Retry 针对不同的响应进行重试 retries、statuses、methods、series
RequestSize 设置允许接收最大请求包的大小。如果请求包大小超过设置的值,则返回 413 Payload TooLarge 请求包大小,单位为字节,默认值为5M
ModifyRequestBody 在转发请求之前修改原始请求体内容 修改后的请求体内容
ModifyResponseBody 修改原始响应体的内容 修改后的响应体内容

详细文档可点击前往 spring-cloud-gateway/2.2.3.RELEASE/reference/html/#gatewayfilter-factories

简单测试:SetStatus :配置文件如下

server:
  port: 7777
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #让gateway可以发现nacos中的微服务
      routes: # 路由数组  指当请求满足什么样的条件的时候,转发到哪个微服务上
        - id: nacosxfz_route #当前路由标识,要求唯一 (默认值uuid,一般不用,需要自定义)
          uri: lb://test-scz #请求最终要被转发的地址   lb指的是从nacos中按照名称获取微服务,并遵循负载均衡策略
          order: 1 #路由优先级,数字越小,优先级越高
          predicates: #断言 判断条件,返回值是boolean 转发请求要返回的条件 (可以写多个)、
            - Path=/scz_server/** #当请求路径满足path指定的规则时,此路由信息才会正常转发
            - Method=POST
          filters: #过滤器(在请求传递过程中,对请求做一些手脚)
            - StripPrefix=1 # 在请求转发之前去掉一层路径
            - SetStatus=66666 #编辑返回的状态码为 6666
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

在这里插入图片描述
测试成功

自定义局部过滤器

还是老问题,我们会需要自己的业务逻辑,那么内置的局部过滤器就无法满足我们的需求,我们需要自定义局部过滤器。

ps(这个和自定义断言极其相似)

现在有一个业务,需要我们手动配置,当访问某个微服务的时候,是否开启惊喜大礼包。

首先添加自定义的配置。
在这里插入图片描述
紧接编写配置类:

/**
 * 这是一个自定义的过滤器工厂类,要求有两个
 * 名字必须是 配置+GatewayFilterFactory  本类的配置字段是 Surprise
 * 必须继承 AbstractGatewayFilterFactory <配置类>
 */
@Component
@Slf4j
public class SurpriseGatewayFilterFactory extends AbstractGatewayFilterFactory<SurpriseGatewayFilterFactory.Config> {
    
    
    
    public SurpriseGatewayFilterFactory() {
    
    
        super(SurpriseGatewayFilterFactory.Config.class);
    }
    
    /**
     * 读取配置文件的中参数值 给他赋值到配置类中的属性上
     *
     * @return 配置类的数据
     */
    @Override
    public List<String> shortcutFieldOrder() {
    
    
        return Collections.singletonList("flag");
    }

    /**
     * 断言逻辑的具体内容
     *
     * @param config 当前断言的配置读取
     * @return 过滤结果
     */
    @Override
    public GatewayFilter apply(Config config) {
    
    
        return (exchange, chain) -> {
    
    
            if (config.flag) {
    
    
                log.info("仙剑惊喜大礼包- 土灵珠 ");
            }
            return chain.filter(exchange);
        };
    }
    
    @Data
    @NoArgsConstructor
    public static class Config {
    
    
        private boolean flag;
    }

}

ps: 这个类的名称 大有玄机 ,需要你自定义的属性名称 + GatewayFilterFactory这个是固定用法

同样可以参考:

在这里插入图片描述
这些类的写法。

此时进行访问验证:
在这里插入图片描述
自定义过滤器验证成功。

全局过滤器

Global Filters

The GlobalFilter interface has the same signature as GatewayFilter. These are special filters that are conditionally applied to all routes.
在这里插入图片描述
我们其实已经简单的运用了 LoadBalancer 若有需要,可参考文档:

spring-cloud-gateway/2.2.3.RELEASE/reference/html/#global-filters

自定义全局过滤器

这个就经常用到了,比如说验证是否登入?

一般的 sso 会返回登入信息,验证token,设备信息等等,这边用最简单的 token 进行例子编写。

这时候配置文件无需修改,因为是全局配置。

添加一个实现类: 目标:让 Cookies 中 没有携带 token 的无法访问并且返回 401。

/**
 * 自定义全局过滤器
 * 必须实现  GlobalFilter, Ordered 接口
 */
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
    
    

    /**
     * 用于编写过滤器逻辑
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    
    
        //简单判断,仅用于测试,真实业务可别这么写
        HttpCookie token = exchange.getRequest().getCookies().getFirst("token");
        if(null == token){
    
    
            //没有携带token返回 401
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return  exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

    /**
     * 用来标识当前用户的优先级,返回值越小,优先级越高
     * @return 数值
     */
    @Override
    public int getOrder() {
    
    
        return 0;
    }
}

测试:

无携带token。

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_29064815/article/details/107236161