soul网关的 divide 插件处理 http 调用流程
本文简单分析 divide 如何对http请求进行转发
请求全部会调用 SoulWebHandler.handle()方法,然后会调用new DefaultSoulPluginChain(plugins).execute(exchange)方法。plugins 则是 soul网关的所有插件集合, exchange 包含当前请求的所有内容。这里使用责任链设计模式依次对soul插件进行遍历
public Mono<Void> execute(final ServerWebExchange exchange) {
return Mono.defer(() -> {
if (this.index < plugins.size()) {
// 循环遍历soul的所有插件
SoulPlugin plugin = plugins.get(this.index++);
// 判断是否跳过当前插件, 默认均为 false
Boolean skip = plugin.skip(exchange);
if (skip) {
return this.execute(exchange);
}
// 当前插件处理请求
return plugin.execute(exchange, this);
}
return Mono.empty();
});
}
插件列表中第一个是 GlobalPlugin ,这是一个全局插件,查看此插件的 execute() 方法
public Mono<Void> execute(final ServerWebExchange exchange, final SoulPluginChain chain) {
// 获取请求信息
final ServerHttpRequest request = exchange.getRequest();
// 请求头信息
final HttpHeaders headers = request.getHeaders();
final String upgrade = headers.getFirst("Upgrade");
SoulContext soulContext;
// 如果 Upgrade为空或者 不是websocket请求
if (StringUtils.isBlank(upgrade) || !"websocket".equals(upgrade)) {
// 创建 soul 上下文, divide插件的 http请求会 执行这里
soulContext = builder.build(exchange);
} else {
final MultiValueMap<String, String> queryParams = request.getQueryParams();
soulContext = transformMap(queryParams);
}
// 设置当前请求的上下文
exchange.getAttributes().put(Constants.CONTEXT, soulContext);
// 继续执行责任链
return chain.execute(exchange);
}
这里可以看下 builder.build(exchange) 方法
public SoulContext build(final ServerWebExchange exchange) {
final ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
// 本地缓存的 metaData 具体为 请求路径 -> 请求路径对应的下游服务信息
MetaData metaData = MetaDataCache.getInstance().obtain(path);
if (Objects.nonNull(metaData) && metaData.getEnabled()) {
exchange.getAttributes().put(Constants.META_DATA, metaData);
}
// 根据metaData信息设置上下文信息
return transform(request, metaData);
}
MetaData 信息对应控制台中的元数据信息

如果没有元数据信息则当前请求默认为 http 类型。
执行完 GlobalPlugin 插件后还会执行 sign 等其他插件,我们暂时略过,因为目前是 divide 插件,直接跳到插件

在 dividePlugin 中先回调用其父类 AbstractSoulPlugin.execute()
public Mono<Void> execute(final ServerWebExchange exchange, final SoulPluginChain chain) {
String pluginName = named();
// 根据插件名称获取插件数据
final PluginData pluginData = BaseDataCache.getInstance().obtainPluginData(pluginName);
if (pluginData != null && pluginData.getEnabled()) {
// 获取插件的 selector 列表(可在控制台查看到)
final Collection<SelectorData> selectors = BaseDataCache.getInstance().obtainSelectorData(pluginName);
if (CollectionUtils.isEmpty(selectors)) {
return handleSelectorIsNull(pluginName, exchange, chain);
}
// 根据规则过滤得到一个 selector
final SelectorData selectorData = matchSelector(exchange, selectors);
if (Objects.isNull(selectorData)) {
return handleSelectorIsNull(pluginName, exchange, chain);
}
selectorLog(selectorData, pluginName);
// 再次过滤获取 rule 列表
final List<RuleData> rules = BaseDataCache.getInstance().obtainRuleData(selectorData.getId());
if (CollectionUtils.isEmpty(rules)) {
return handleRuleIsNull(pluginName, exchange, chain);
}
RuleData rule;
// 获取匹配到的 rule
if (selectorData.getType() == SelectorTypeEnum.FULL_FLOW.getCode()) {
//get last
rule = rules.get(rules.size() - 1);
} else {
rule = matchRule(exchange, rules);
}
if (Objects.isNull(rule)) {
return handleRuleIsNull(pluginName, exchange, chain);
}
ruleLog(rule, pluginName);
// 调用 真正的 DividePlugin 的方法
return doExecute(exchange, chain, selectorData, rule);
}
return chain.execute(exchange);
}
真正的 DividePlugin 的方法
protected Mono<Void> doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, final RuleData rule) {
// 获取之前设置好的 上下文
final SoulContext soulContext = exchange.getAttribute(Constants.CONTEXT);
assert soulContext != null;
// 过滤后获取的 rule
final DivideRuleHandle ruleHandle = GsonUtils.getInstance().fromJson(rule.getHandle(), DivideRuleHandle.class);
// 下游服务列表
final List<DivideUpstream> upstreamList = UpstreamCacheManager.getInstance().findUpstreamListBySelectorId(selector.getId());
if (CollectionUtils.isEmpty(upstreamList)) {
log.error("divide upstream configuration error: {}", rule.toString());
Object error = SoulResultWrap.error(SoulResultEnum.CANNOT_FIND_URL.getCode(), SoulResultEnum.CANNOT_FIND_URL.getMsg(), null);
return WebFluxResultUtils.result(exchange, error);
}
final String ip = Objects.requireNonNull(exchange.getRequest().getRemoteAddress()).getAddress().getHostAddress();
// 根据配置的负载策略获取到一个下游服务
DivideUpstream divideUpstream = LoadBalanceUtils.selector(upstreamList, ruleHandle.getLoadBalance(), ip);
if (Objects.isNull(divideUpstream)) {
log.error("divide has no upstream");
Object error = SoulResultWrap.error(SoulResultEnum.CANNOT_FIND_URL.getCode(), SoulResultEnum.CANNOT_FIND_URL.getMsg(), null);
return WebFluxResultUtils.result(exchange, error);
}
// set the http url 构建真实服务 url
String domain = buildDomain(divideUpstream);
String realURL = buildRealURL(domain, soulContext, exchange);
exchange.getAttributes().put(Constants.HTTP_URL, realURL);
// set the http timeout
exchange.getAttributes().put(Constants.HTTP_TIME_OUT, ruleHandle.getTimeout());
exchange.getAttributes().put(Constants.HTTP_RETRY, ruleHandle.getRetry());
// 继续执行调用链
return chain.execute(exchange);
}
到这里请求都已经别封装好。
随后调用到 WebClientPlugin 的 execute 方法 请求下游服务

最后执行 WebClientResponsePlugin 插件来处理下游服务的response

简单的分析就先到这里,其他功能后续在分析,如果文章那里有错误希望大家指出
Soul网关divide插件处理HTTP调用流程分析
724

被折叠的 条评论
为什么被折叠?



