天天看点

Nacos网关gateway的断言,自定义断言,过滤器使用

作者:没得感情的西瓜

接上次网关的初步搭架成功后,看看断言和过滤器的如何操作。

上篇文章环境搭建已经ok,这次是在上篇的基础上开始操作。

上篇说了断言主要是配置文件中的application-dev.properties配置文件中spring.cloud.gateway.routes[0].predicates[0]的属性配置,上次我们只使用Path路径的断言,其实还有很多关键字可以使用

#设置路由断言,代理servicerId为provider-xg的/provider-xg/路径
spring.cloud.gateway.routes[0].predicates[0]=Path=/provider-route/**           

先搭好环境:Nacos注册中心,调用服务

不清楚的朋友可以看看前面的帖子

Nacos网关gateway的断言,自定义断言,过滤器使用

开始根据规则来进行断言

因为规则太多我把对应规则的成功例子列出,测试几个,有兴趣的朋友可以自行测试其他。

#设置路由断言
#Path 代表路径断言
spring.cloud.gateway.routes[0].predicates[0]=Path=/provider-route/**
#After 代表时间之后都可以访问的断言
spring.cloud.gateway.routes[0].predicates[1]=After=2022-08-31T23:59:59.789+08:00[Asia/Shanghai]
#After 代表时间之前都可以访问的断言
spring.cloud.gateway.routes[0].predicates[2]=Before=2022-12-31T23:59:59.789+08:00[Asia/Shanghai]
#Method 代表支持方法类型,可支持多个,逗号分隔
spring.cloud.gateway.routes[0].predicates[3]=Method=Get,Post
#RemoteAddr 代表支持ip的断言支持多个,逗号分隔
spring.cloud.gateway.routes[0].predicates[4]=RemoteAddr=10.45.12.61,10.45.12.63
#自定义断言
spring.cloud.gateway.routes[0].predicates[5]=Test=dxg
#请求转发时会拦截路径/provider-route开头的,并且去掉/provider-route再开始转发到对应微服务接口,1的意思去掉一个前缀,2就是去掉俩个
spring.cloud.gateway.routes[0].filters[0]=StripPrefix=1           

我们测试下时间断言:

把After改为当前时间之后,因为时间没到,会访问失败,应该访问不了,改为今年12月

spring.cloud.gateway.routes[0].predicates[1]=After=2022-12-31T23:59:59.789+08:00[Asia/Shanghai]           

访问测试:正常报错,断言成功,其他断言大家自行测试

Nacos网关gateway的断言,自定义断言,过滤器使用

下面列出我目前接触到的规则:

  • Path 代表路径断言
  • After 代表时间之后都可以访问的断言
  • After 代表时间之前都可以访问的断言
  • Method 代表支持方法类型,可支持多个,逗号分隔
  • RemoteAddr 代表支持远程地址的断言支持多个,逗号分隔
  • Cookie:接收两个参数, cookie 名字和一个正则表达式。判断请求cookie是否具有给定名称且值与正则表达式匹配。
spring.cloud.gateway.routes[0].predicates[3]=Cookie=chocolate, ch.           
  • Header :接收两个参数,标题名称和正则表达式。 判断请求Header 是否具有给定名称且值与正则表达式匹配。 key value
spring.cloud.gateway.routes[0].predicates[n]=Header=X-Request-Id, \d+           
  • Host :接收一个参数,主机名模式。判断请求的Host 是否满足匹配规则。
spring.cloud.gateway.routes[0].predicates[n]=Host=**.hostName.org           
  • Query :接收两个参数,请求 param 和正则表达式, 判断请求参数是否具有给定名称且值与正则表达式匹配。
spring.cloud.gateway.routes[0].predicates[n]=Query=xg, dag.           
  • 基于路由权重的断言工厂 Weight:接收一个 [ 组名 , 权重 ], 然后对于同一个组内的路由按照权重转发
spring.cloud.gateway.routes[0].predicates[n]=Weight= groupName, 9           

如果上述规则不满足需求的话还可以自定义断言

先说一个场景,只支持某个人来访问接口,这时候我们需要定制化一个断言。

自定义断言有几个要求:

1.必须继承AbstractRoutePredicateFactory

2.类名称必须xxx加上RoutePredicateFactory作为结尾,其中xxx就是路由断言新增的配置规则,可以在断言中添加

3.shortcutFieldOrder方法绑定路由中的配置,即可去读

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

现在贴上实现类代码:

package com.gateway.predicate;

import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;

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

/**
 * @author xg
 */
@Component
public class TestRoutePredicateFactory extends AbstractRoutePredicateFactory<TestRoutePredicateFactory.Config> {
    public TestRoutePredicateFactory() {
        super(TestRoutePredicateFactory.Config.class);
    }

    //读取配置文件中的内容并配置给配置类中的属性,即新增的断言配置项
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("name");
    }

    @Override
    public Predicate<ServerWebExchange> apply(TestRoutePredicateFactory.Config config) {
        return (exchange) -> {
          // 从请求中获取配置项,也可配置在其他地方获取,看个人需求
            String name = exchange.getRequest().getQueryParams().getFirst("name");
            if(StringUtils.isNotEmpty(name)){
               if(name.equals(config.getName())) {
                   return true;
               }
            }
            return false;
        };
    }

    @Data
    @NoArgsConstructor
    public static class Config{
        private String name;
    }
}
           

根据自定义断言类建立,我们就产生新的断言规则关键字,这个关键字其实就是自定义断言名称去掉RoutePredicateFactory的字符串也就是Test,路由配置为下面

#自定义断言
spring.cloud.gateway.routes[0].predicates[5]=Test=dxg           

现在我们测试带个name交xg的,我们配置的是dxg,所以会访问失败

Nacos网关gateway的断言,自定义断言,过滤器使用

接下来测试dxg,这次应该成功:

Nacos网关gateway的断言,自定义断言,过滤器使用

请求成功

自定义断言结束。

接下来看看过滤器

过滤器

定义全局过滤器,需要继承俩个接口GlobalFilter, Ordered,

GlobalFilter是具体过滤逻辑,Ordered是定义过滤器的顺序,就是说可以定义多个过滤器,这个用来指定过滤器的执行顺序。

package com.gateway.filters;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.fastjson.JSONObject;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

/**
 * @author xg
 */
@Component
public class TestFilter implements GlobalFilter, Ordered {

    /**
     * 过滤器的具体逻辑
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        String token = request.getQueryParams().getFirst("token");

        // 判断token是否符合条件,正确则进入接口调用流程。否则不合法请求,直接返回
        if(StringUtils.isNotEmpty(token)) {
            // token的具体判断逻辑
            if("1q2w3e4r".equals(token)) {
                // 校验通过,走接下来接口逻辑或者其他过滤器
                return chain.filter(exchange);
            }
        }

        // 不合法token,直接返回,提示没有权限
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        DataBuffer buffer = response.bufferFactory().wrap(JSONObject.toJSONString("token is illegal.").getBytes(StandardCharsets.UTF_8));

        return response.writeWith(Flux.just(buffer));
    }

    /**
     * 用来定义过滤器的执行顺序,升序执行
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}
           

我们定义的过滤器必须携带token,而且必须符合我们定义的规则才可通过,否则属于不合法的请求,不允许访问。

我们随便携带了token,不符合条件来访问试试:

http://10.45.12.63:8099/provider-route/provider/get?name=dxg&token=1234

Nacos网关gateway的断言,自定义断言,过滤器使用

直接报token不合法,接下来我们试试合法的token

http://10.45.12.63:8099/provider-route/provider/get?name=dxg&token=1q2w3e4r

Nacos网关gateway的断言,自定义断言,过滤器使用

请求成功,到此,我们的过滤器就创建成功了。当然我们的逻辑很是简单,真正的过滤器可以做很多功能,token鉴权,日志打印等等。有兴趣可以自己去试试。如果觉得不错,希望大家点赞加关注哦。

Nacos网关gateway的断言,自定义断言,过滤器使用
  • 事物的精粹,总在它离去时方才显现
  • 愿大家珍惜所拥有的,不负韶华,以梦为马,历尽千帆,归来仍是少年。

继续阅读