soul网关学习五之divide插件的http调用

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);
    }

到这里请求都已经别封装好。
随后调用到 WebClientPluginexecute 方法 请求下游服务
在这里插入图片描述
最后执行 WebClientResponsePlugin 插件来处理下游服务的response
在这里插入图片描述
简单的分析就先到这里,其他功能后续在分析,如果文章那里有错误希望大家指出

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值