接上次网关的初步搭架成功后,看看断言和过滤器的如何操作。
上篇文章环境搭建已经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注册中心,调用服务
不清楚的朋友可以看看前面的帖子
开始根据规则来进行断言
因为规则太多我把对应规则的成功例子列出,测试几个,有兴趣的朋友可以自行测试其他。
#设置路由断言
#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]
访问测试:正常报错,断言成功,其他断言大家自行测试
下面列出我目前接触到的规则:
- 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,所以会访问失败
接下来测试dxg,这次应该成功:
请求成功
自定义断言结束。
接下来看看过滤器
过滤器
定义全局过滤器,需要继承俩个接口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
直接报token不合法,接下来我们试试合法的token
http://10.45.12.63:8099/provider-route/provider/get?name=dxg&token=1q2w3e4r
请求成功,到此,我们的过滤器就创建成功了。当然我们的逻辑很是简单,真正的过滤器可以做很多功能,token鉴权,日志打印等等。有兴趣可以自己去试试。如果觉得不错,希望大家点赞加关注哦。
- 事物的精粹,总在它离去时方才显现
- 愿大家珍惜所拥有的,不负韶华,以梦为马,历尽千帆,归来仍是少年。