fizz 2.0 重构了插件机制,使插件功能及用法与 org.springframework.web.server.WebFilter 一致,新机制兼容旧插件,但新插件的开发应基于新机制。
新插件开发,在插件定义、配置、应用方面与旧的一样,区别在于 gateway 新设计
public interface FizzPluginFilter {
public Mono<Void> filter(ServerWebExchange exchange, Map<String, Object> config);
}
类似 WebFilter,插件实现此接口即可。
下面以一个例子演示插件的开发,假设用户登录系统后,系统生成对应的 token,以 token (key) -> 用户 id (value) 的形式存储于 redis,用户的后续请求需带上 token,否则无法访问系统逻辑,若所带 token 在系统中不存在,也拒绝访问。此逻辑可通过一个插件实现:
@Component(RedisAuthPlugin.REDIS_AUTH_PLUGIN) // 必须,且要和管理后台配置的插件id一致
public class RedisAuthPlugin implements FizzPluginFilter {
private static final Logger log = LoggerFactory.getLogger(RedisAuthPlugin.class);
public static final String REDIS_AUTH_PLUGIN = "redisAuthPlugin";
@Resource(name = AggregateRedisConfig.AGGREGATE_REACTIVE_REDIS_TEMPLATE)
private ReactiveStringRedisTemplate redisTemplate;
@Override
public Mono<Void> filter(ServerWebExchange exchange, Map<String, Object> config) {
String customConfig = (String) config.get(PluginConfig.CUSTOM_CONFIG); // 获取自定义的插件配置
log.info("custom plugin config: " + customConfig);
doSomething();
String tk = exchange.getRequest().getQueryParams().getFirst("token"); // 获取客户端请求携带的 token
return
redisTemplate.opsForValue().get(tk).defaultIfEmpty(Constants.Symbol.EMPTY) // 检查 redis 中是否存在 tk
.flatMap(
user -> {
if (user == Constants.Symbol.EMPTY) {
return WebUtils.buildDirectResponse(exchange, HttpStatus.OK, null, "不存在 token " + tk); // 拒绝当前请求
} else {
exchange.getAttributes().put("11", "22"); // 往后续插件或逻辑传递参数
Mono next = FizzPluginFilterChain.next(exchange); // 执行下一个插件或后续逻辑
return next.defaultIfEmpty(ReactorUtils.NULL).flatMap(
nil -> {
doAfterNext(); // 当 next 完成时执行一些逻辑
return Mono.empty();
}
);
}
}
);
}
public void doSomething() {
}
public void doAfterNext() {
log.info("do after next plugin done");
}
}
例子代码:https://github.com/wehotel/fizz-examples/tree/master/fizz-example-plugin,例子的运行等,参其中的 README.md。