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。