做网站需要的技术,沧州模板建站平台,邢台365生活网,360网站图标怎么做目录
一、FilterFactory 分析
1.1、前置知识
1.2、分析源码
1.2.1、整体分析
1.2.2、源码分析
1.3、手写源码
1.3.1、基础框架
1.3.2、实现自定义局部过滤器
1.3.3、加参数的自定义局部过滤器器 一、FilterFactory 分析 1.1、前置知识
前面的学习我们知道#xff0c…目录
一、FilterFactory 分析
1.1、前置知识
1.2、分析源码
1.2.1、整体分析
1.2.2、源码分析
1.3、手写源码
1.3.1、基础框架
1.3.2、实现自定义局部过滤器
1.3.3、加参数的自定义局部过滤器器 一、FilterFactory 分析 1.1、前置知识
前面的学习我们知道GatewayFilter是网关中提供的一种过滤器可以对进入网关的请求和微服务返回的响应做处理同时springcloud 也提供了一些内置的 filter.
比如StripPrefix表示给请求的 url 中去表指定的 n 个前缀路由例如 - StripPrefix2 那么如果你原本的请求是路由是 /user/list/get 那么经过 StripPrefix 处理后就会变成 /get. 如果我们需要自己去实现一个像这样的局部过滤器该怎么实现呢 1.2、分析源码
1.2.1、整体分析
例如 StripPrefix他继承了 AbstractGatewayFilterFactory 这个抽象类. 这里暗含了一层意思在 application.yml 配置文件中可以在 filters 配置里写上这个类的前缀 StripPrefix就表示这个类后面的 GatewayFilterFactory 是固定写法就表示他是一个网关过滤器. 进一步的如果我们要自定义一个局部过滤器例如身份认证 Token 过滤器我们就创建一个类命名为Token GatewayFilter然后继承 AbstractGatewayFilterFactory 抽象类就表示他是一个局部过滤器.
1.2.2、源码分析
源码如下
public class StripPrefixGatewayFilterFactory extends AbstractGatewayFilterFactoryConfig {public static final String PARTS_KEY parts;public StripPrefixGatewayFilterFactory() {super(Config.class);}public ListString shortcutFieldOrder() {return Arrays.asList(parts);}public GatewayFilter apply(final Config config) {return new GatewayFilter() {public MonoVoid filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request exchange.getRequest();ServerWebExchangeUtils.addOriginalRequestUrl(exchange, request.getURI());String path request.getURI().getRawPath();String[] originalParts StringUtils.tokenizeToStringArray(path, /);StringBuilder newPath new StringBuilder(/);for(int i 0; i originalParts.length; i) {if (i config.getParts()) {if (newPath.length() 1) {newPath.append(/);}newPath.append(originalParts[i]);}}if (newPath.length() 1 path.endsWith(/)) {newPath.append(/);}ServerHttpRequest newRequest request.mutate().path(newPath.toString()).build();exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, newRequest.getURI());return chain.filter(exchange.mutate().request(newRequest).build());}public String toString() {return GatewayToStringStyler.filterToStringCreator(StripPrefixGatewayFilterFactory.this).append(parts, config.getParts()).toString();}};}public static class Config {private int parts 1;public Config() {}public int getParts() {return this.parts;}public void setParts(int parts) {this.parts parts;}}
}extends AbstractGatewayFilterFactoryConfig 继承 AbstractGatewayFilterFactory 表示他是一个局部过滤器. 传入一个泛型 Config是一个静态内部类是因为在配置 filters 的时候可能需要给参数指定具体的值例如 - StripPrefix2而 Config 就是来处理这里的 2 这个值的.public static final String PARTS_KEY parts 这里就是定义一个常量后面会用上.StripPrefixGatewayFilterFactory() 构造方法需要给父类 AbstractGatewayFilterFactory 传递 Config 参数前面分析过了将来在 apply 方法中会用上.Config是一个静态内部类描述了配置 filters 时具体要给参数指定的值并提供了 get 和 set 方法. 这个类就需要传递给父类 AbstractGatewayFilterFactory最后回传给 apply 方法在 apply 方法中使用.如果不想给参数指定值就可以不写 Config 中的内容.shortcutFieldOrder()这个方法是用来指定 filters 配置中参数值的顺序. 也就是说如果 Config 个中如果有多个参数那么你在配置 filters 时指定参数的多个值顺序是怎样的他就是用来指定顺序的.apply(Config config)局部过滤器的核心类用来描述过滤规则的. 这里的参数 Config 就是刚刚讲到的 静态内部类先传递给父类然后再回传给了 apply 方法之后我们就可以直接在 apply 方法中去使用 Config 类中的参数. 1.3、手写源码
1.3.1、基础框架
按照上述分析不难写出大概模样例如我们可以模仿源码创建包 filter.factory 然后在这个包下定义一个 Token 局部过滤器如下
Component // 表示在工厂中创建对象不能少
public class TokenGatewayFilterFactory extends AbstractGatewayFilterFactoryTokenGatewayFilterFactory.Config {public TokenGatewayFilterFactory() {super(Config.class);}/*** 核心方法: 处理过滤* param config* return*/Overridepublic GatewayFilter apply(Config config) {return new GatewayFilter() {Overridepublic MonoVoid filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 处理过滤逻辑......return chain.filter(exchange);}};}Overridepublic ListString shortcutFieldOrder() {return super.shortcutFieldOrder();}public static class Config {}}那么我们就可以在配置文件中添加这个自定义的局部过滤器 1.3.2、实现自定义局部过滤器
例如自定义一个 Token 局部过滤器那么就可以创建一个类 filter.factory.TokenGatewayFilterFactory
在 apply 中的过滤逻辑就是判断前端是否传入 token如果没有就抛异常如果有就去 redis 上看看是否存在这个 token如果存在就放行不存在就抛异常.
Slf4j
Component // 表示在工厂中创建对象
public class TokenGatewayFilterFactory extends AbstractGatewayFilterFactoryTokenGatewayFilterFactory.Config {Autowiredprivate StringRedisTemplate redisTemplate;public TokenGatewayFilterFactory() {super(Config.class);}/*** 核心方法: 处理过滤* param config* return*/Overridepublic GatewayFilter apply(Config config) {return new GatewayFilter() {Overridepublic MonoVoid filter(ServerWebExchange exchange, GatewayFilterChain chain) {//1.获取 token 信息//由于 header 中 key 可以重复(包括 parma 也是如此)因此获取到的是一个 ListListString tokens exchange.getRequest().getHeaders().get(RedisPrefix.TOKEN_KEY);if(tokens null) {throw new RuntimeException(没有 token 令牌);}String tokenValue tokens.get(0);log.info(token: {}, tokenValue);//2.比较 redis 上的 token 数据是否一致(redis 上存储的数据格式为: token前缀 value)if(!redisTemplate.hasKey(RedisPrefix.TOKEN_KEY tokenValue)) {throw new RuntimeException(token 令牌不合法);}return chain.filter(exchange);}};}Overridepublic ListString shortcutFieldOrder() {return super.shortcutFieldOrder();}public static class Config {}}a例如 redis 存储的数据为 b执行结果如下 c如果没有 token 数据响应如下 d如果有 token但是 token 值错误响应如下 1.3.3、加参数的自定义局部过滤器器
如果在配置 filters 的时候要指定一些参数例如 isRequireboolean类型表示是否传nameString 类型.
那么就可以在 Config 静态内部类中描述然后在 shortcutFieldOrder() 方法中指定顺序最后就可以在 apply 中拿到对应的参数如下
Slf4j
Component // 表示在工厂中创建对象
public class TokenGatewayFilterFactory extends AbstractGatewayFilterFactoryTokenGatewayFilterFactory.Config {Autowiredprivate StringRedisTemplate redisTemplate;public TokenGatewayFilterFactory() {super(Config.class);}/*** 核心方法: 处理过滤* param config* return*/Overridepublic GatewayFilter apply(Config config) {return new GatewayFilter() {Overridepublic MonoVoid filter(ServerWebExchange exchange, GatewayFilterChain chain) {log.info(config isRequire: {}, config.isRequire());log.info(config name: {}, config.getName());//1.拿到 Config 中自定义的参数 isRequire判断是否要进行过滤if(config.isRequire()) {//2.获取 token 信息//由于 header 中 key 可以重复(包括 parma 也是如此)因此获取到的是一个 ListListString tokens exchange.getRequest().getHeaders().get(RedisPrefix.TOKEN_KEY);if(tokens null) {throw new RuntimeException(没有 token 令牌);}String tokenValue tokens.get(0);log.info(token: {}, tokenValue);//3.比较 redis 上的 token 数据是否一致(redis 上存储的数据格式为: token前缀 value)if(!redisTemplate.hasKey(RedisPrefix.TOKEN_KEY tokenValue)) {throw new RuntimeException(token 令牌不合法);}}return chain.filter(exchange);}};}/*** 指定参数值填写的顺序* return*/Overridepublic ListString shortcutFieldOrder() {return Arrays.asList(require, name);}/*** 提供 filter 配置中的参数值*/public static class Config {private boolean require;private String name;public boolean isRequire() {return require;}public void setRequire(boolean require) {this.require require;}public String getName() {return name;}public void setName(String name) {this.name name;}}}Ps这里的不要命名为 isRequire 会冲突 在配置文件中配置 filters 执行结果如下