选择器和规则匹配
选择器和规则
Soul网关里的插件使用的是责任链的模式进行处理,所有流进网关的流量都会经过每个插件的处理;但是再插件处理之前,流量还需要经过Selector和rule的处理,过滤调不符合规则的流量数据。
话不多说,直接看代码;
选择器和规则器的代码位置
如图所示,选择器和规则的代码再soul-plugin
- soul-plugin-base
- AbstractSoulPlugin
下;
代码解析
- 一个插件对应多个选择器,一个选择器对应多个规则;在进行选择器和规则选择的时候,首先判断选择器存不存在,如果不存在,直接判断插件是否为waf\divide\dubbo\springcloud,如果不是其中插件则直接打印一条错误日志,插件执行失败,匹配不到;
- 如果存在则会继续向下去匹配规则;规则的匹配和选择器的匹配一样,通过选择器去查询对应的规则,同时和uri进行匹配,获取对应的规则;如果规则为空则断插件是否为waf\divide\dubbo\springcloud,如果不是其中插件则直接打印一条错误日志,插件执行失败,匹配不到;
- 流程如图所示:
@Override
public Mono<Void> execute(final ServerWebExchange exchange, final SoulPluginChain chain) {
// 获取plugin name
String pluginName = named();
// 获取插件的信息
final PluginData pluginData = BaseDataCache.getInstance().obtainPluginData(pluginName);
if (pluginData != null && pluginData.getEnabled()) {
// obtainSelectorData会通过plugin 名称去获取该插件的选择器
final Collection<SelectorData> selectors = BaseDataCache.getInstance().obtainSelectorData(pluginName);
if (CollectionUtils.isEmpty(selectors)) {
// 如果选择器为空, 首先判断是否为waf插件(防火墙),再判断是否为divide, dubbo, spring-cloud,
// 只要是其中一种,就直接执行插件的处理方法
return handleSelectorIsNull(pluginName, exchange, chain);
}
// 更具响应的uri和selector进行过滤,拿到对应的selectorData,如果有多条直接默认第一条选择器
final SelectorData selectorData = matchSelector(exchange, selectors);
if (Objects.isNull(selectorData)) {
return handleSelectorIsNull(pluginName, exchange, chain);
}
selectorLog(selectorData, pluginName);
// 通过选择器ID拿到路由Id
final List<RuleData> rules = BaseDataCache.getInstance().obtainRuleData(selectorData.getId());
// 如果规则为空,判断插件是否是waf,divide,dubbo,spring cloud,如果是的话直接执行插件操作
// 如果不是上述插件,将包 "Can not match plugin" 的异常
if (CollectionUtils.isEmpty(rules)) {
return handleRuleIsNull(pluginName, exchange, chain);
}
RuleData rule;
if (selectorData.getType() == SelectorTypeEnum.FULL_FLOW.getCode()) {
//get last
rule = rules.get(rules.size() - 1);
} else {
rule = matchRule(exchange, rules);
}
// 如果规则为空,判断插件是否是waf,divide,dubbo,spring cloud,如果是的话直接执行插件操作
// 如果不是上述插件,将包 "Can not match plugin" 的异常
if (Objects.isNull(rule)) {
return handleRuleIsNull(pluginName, exchange, chain);
}
ruleLog(rule, pluginName);
// 执行插件操作
return doExecute(exchange, chain, selectorData, rule);
}
return chain.execute(exchange);
}