scg断言种类及POST请求多次处理body解决版本

一、版本
sc版本:Greenwich.RELEASE
相应scg版本:spring-cloud-starter-gateway:2.1.0.RELEASE
二、断言种类 scg断言种类及POST请求多次处理body解决版本_第1张图片
scg断言种类及POST请求多次处理body解决版本_第2张图片
其中ReadBodyPredicatechaFactory也是实现RoutePredicateFactory,继承图如下:
scg断言种类及POST请求多次处理body解决版本_第3张图片
三、ReadBodyPredicateFactory配置方式
查看官网介绍,2.1.x和2.2.x都没有关于该断言的说明
scg断言种类及POST请求多次处理body解决版本_第4张图片
这里看出官方给出的示例都是基于yml的
1)javaconfig

builder.routes()
.route(“get_route”, r -> r.path("/")
.and().method(“GET”)
.filters(f -> f.filter(myFilter))
.uri(myUrl))
.route(“post_route”, r -> r.path("/
")
.and().method(“POST”)
.and().readBody(String.class, requestBody -> {return true;})
.filters(f -> f.filter(myFilter))
.uri(myUrl))

参考scg issues-152
其中:readBody两个参数其实是其内部类config属性scg断言种类及POST请求多次处理body解决版本_第5张图片第一个就是body传递的对象类型,这里是字符串,也可以是Object对象,或者自定义对象
第二个参数是个Predict实现类,这里这种方式就不用自己实现,采用用自己(也就是PredicateFactory的实现类,可以简写)ReadBodyPredicateFactory.默认返回true,表示断言总是正确,读取body.
2) 配置文件

spring.cloud.gateway.routes[0].predicates[1].name=ReadBodyPredicateFactory
spring.cloud.gateway.routes[0].predicates[1].args.inClass=#{T(String)}
spring.cloud.gateway.routes[0].predicates[1].args.predicate=#{@testPredicate}

需要提供一个bean,也就是配置文件中的testPredicate


```java
@Component
public class TestPredicate implements Predicate {
    @Override
    public boolean test(Object o) {
        return true;
    }
}```

  1. PredicateDefinition
RouteDefinition routeDefinition = new RouteDefinition();
PredicateDefinition readBodyPredicateDefinition = new PredicateDefinition();       readBodyPredicateDefinition.setName("ReadBodyPredicateFactory");
readBodyPredicateDefinition.addArg("inClass","#{T(Object)}");
readBodyPredicateDefinition.addArg("predicate", "#{@testPredicate}");
routeDefinition.setPredicates(Arrays.asList(readBodyPredicateDefinition));

这里predicate采用占位符方式,里面的testPredicate也需要自定义注册。

四、ReadBodyPredicateFactory方式源码解析
上面第三种PredicateDefinition方式,不知道如何定义名字和参数的过程:
定义断言时名字不知道怎么写?
开始写的ReadBody(参考PathRoutePredicateFactory),结果报没有找到该name.
报错:

java.lang.IllegalArgumentException: Unable to find RoutePredicateFactory with name ReadBody at org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator.lookup(RouteDefinitionRouteLocator.java:216) ~[spring-cloud-gateway-core-2.1.0.RELEASE.jar:2.1.0.RELEASE]

找到这个堆栈代码处,找到断言名称集合
scg断言种类及POST请求多次处理body解决版本_第6张图片
发现读取body的名称为全称,这个命名规则跟其他的不大一样~~!
然后参数组成结构是什么样喃,key是什么,value又是什么喃?
其实这个key就是内部类config的属性名,那value该怎么写喃,发现value只能是个字符串,项目中body为object,那么是不是就写Object.class.getName()。结果报错。跟踪堆栈
scg断言种类及POST请求多次处理body解决版本_第7张图片
发现这里参数值要先占位符替换才能变成对象。突然想起来第二个配置参数的方式。一测试,果然是正解。
另外补充一点,从这里可以看出,路由配置初始化过程是从RouteDefinitionRouteLocator的lookup方法过程中完成的。这个方法启动时也会执行哦。
五、参考
1.
post方式多次处理body
body.subscribe缓存方式
ServerWebExchangeDecorator包装类缓存
这里对网上主流的包装类进行了引用,开始同事也是采用包装类缓存方式,当spring boot 在2.0.x时可以获取到,但是升级到2.1.x发现无法获取到。并且楼主也提到body长度截取问题,事实上楼主也没没有采用这种方式。
2.借鉴ReadBody或者ModifyBody来多次读取Body

你可能感兴趣的:(学习)