soul网关springcloud用例学习:springcloud用例运行与问题分析

今日目标

soul网关作为springcloud网关的用例学习,对应用例工程 soul-examples-springcloud

艰难的过程

今天应该算是自己第一次从代码层面接触springcloud,在黑暗中摸索springcloud和soul网关的结合,中间遇到不少问题,且慢慢道来。

  1. 根据之前测试http代理和dubbo代理的经验,先是无脑地启动 admin、bootstrap,然后启动soul-examples-springcloud,从admin前端界面看,springcloud对应的选择器和规则都已自动注册上去,以为一切都很顺利的,然后用postman调用如下接口:
curl -X GET \
  'http://127.0.0.1:9195/springcloud/order/findById?id=5' \
  -H 'Content-Type: application/json' \
  -H 'Postman-Token: 7f6cc848-ce9a-46c9-8fbb-e648520ad5a1' \
  -H 'cache-control: no-cache' \
  -d '{
	"id":"55",
	"name":"abc"
}'

返回如下:

{
    "code": -107,
    "message": "Can not find selector, please check your configuration!",
    "data": null
}
  1. 首先看测试用例那边有没有异常日志,发现确实有,还是关于eureka的,去官网查了下,需要在bootstrap的pom.xml下面加入如下依赖:
<!--soul springCloud plugin start-->
  <dependency>
       <groupId>org.dromara</groupId>
       <artifactId>soul-spring-boot-starter-plugin-springcloud</artifactId>
        <version>${last.version}</version>
  </dependency>

  <dependency>
       <groupId>org.dromara</groupId>
       <artifactId>soul-spring-boot-starter-plugin-httpclient</artifactId>
       <version>${last.version}</version>
   </dependency>
   <!--soul springCloud plugin end-->

   <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-commons</artifactId>
        <version>2.2.0.RELEASE</version>
   </dependency>
   <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        <version>2.2.0.RELEASE</version>
   </dependency>

如果使用 eureka 作为 springCloud的注册中心
新增如下依赖:

  <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
       <version>2.2.0.RELEASE</version>
  </dependency>

上述这些依赖在bootstrap是被注掉的,去掉注释即可。

  1. 接着重新启动 admin,bootstrap,eureka以及springcloud example,正常启动,但是调用接口还是返回-107的错误。
  2. 于是还是从org.dromara.soul.web.handler.SoulWebHandler.DefaultSoulPluginChain.execute(ServerWebExchange)这个插件入口处排查,发现SpringCloudPlugin直接被跳过,自然也就没法进入里面的处理路基,于是在这个入口代码添加日志如下:
public Mono<Void> execute(final ServerWebExchange exchange) {
            return Mono.defer(() -> {
                if (this.index < plugins.size()) {
                    SoulPlugin plugin = plugins.get(this.index++);
                    SoulContext body = exchange.getAttribute(Constants.CONTEXT);
                    System.out.println("index:" + this.index + ";handler plugin name:" + plugin.named()
                    		+ "; rpcType:" + Optional.ofNullable(body).orElse(null));
                    
                    Boolean skip = plugin.skip(exchange);
                    if (skip) {
                        return this.execute(exchange);
                    }
                    return plugin.execute(exchange, this);
                }
                return Mono.empty();
            });
        }

在SpringCloudPlugin插件类也添加如下日志,

 public Boolean skip(final ServerWebExchange exchange) {
        final SoulContext body = exchange.getAttribute(Constants.CONTEXT);
        System.out.println("1." + Objects.requireNonNull(body).getRpcType());
        System.out.println("2." + RpcTypeEnum.SPRING_CLOUD.getName());
        return !Objects.equals(Objects.requireNonNull(body).getRpcType(), RpcTypeEnum.SPRING_CLOUD.getName());
    }

用postman发送请求后发现打印日志如下:

index:1;handler plugin name:global; rpcType:null
index:2;handler plugin name:sign; rpcType:SoulContext(module=/springcloud, method=/order/findById, rpcType=http, httpMethod=POST, sign=null, timestamp=null, appKey=null, path=/springcloud/order/findById, contextPath=/springcloud, realUrl=/order/findById, dubboParams=null, startDateTime=2021-01-26T00:52:04.476)
index:3;handler plugin name:waf; rpcType:SoulContext(module=/springcloud, method=/order/findById, rpcType=http, httpMethod=POST, sign=null, timestamp=null, appKey=null, path=/springcloud/order/findById, contextPath=/springcloud, realUrl=/order/findById, dubboParams=null, startDateTime=2021-01-26T00:52:04.476)
index:4;handler plugin name:rate_limiter; rpcType:SoulContext(module=/springcloud, method=/order/findById, rpcType=http, httpMethod=POST, sign=null, timestamp=null, appKey=null, path=/springcloud/order/findById, contextPath=/springcloud, realUrl=/order/findById, dubboParams=null, startDateTime=2021-01-26T00:52:04.476)
index:5;handler plugin name:hystrix; rpcType:SoulContext(module=/springcloud, method=/order/findById, rpcType=http, httpMethod=POST, sign=null, timestamp=null, appKey=null, path=/springcloud/order/findById, contextPath=/springcloud, realUrl=/order/findById, dubboParams=null, startDateTime=2021-01-26T00:52:04.476)
index:6;handler plugin name:resilience4j; rpcType:SoulContext(module=/springcloud, method=/order/findById, rpcType=http, httpMethod=POST, sign=null, timestamp=null, appKey=null, path=/springcloud/order/findById, contextPath=/springcloud, realUrl=/order/findById, dubboParams=null, startDateTime=2021-01-26T00:52:04.476)
index:7;handler plugin name:divide; rpcType:SoulContext(module=/springcloud, method=/order/findById, rpcType=http, httpMethod=POST, sign=null, timestamp=null, appKey=null, path=/springcloud/order/findById, contextPath=/springcloud, realUrl=/order/findById, dubboParams=null, startDateTime=2021-01-26T00:52:04.476)
index:8;handler plugin name:springCloud; rpcType:SoulContext(module=/springcloud, method=/order/findById, rpcType=http, httpMethod=POST, sign=null, timestamp=null, appKey=null, path=/springcloud/order/findById, contextPath=/springcloud, realUrl=/order/findById, dubboParams=null, startDateTime=2021-01-26T00:52:04.476)
1.http
2.springCloud
index:9;handler plugin name:webClient; rpcType:SoulContext(module=/springcloud, method=/order/findById, rpcType=http, httpMethod=POST, sign=null, timestamp=null, appKey=null, path=/springcloud/order/findById, contextPath=/springcloud, realUrl=/order/findById, dubboParams=null, startDateTime=2021-01-26T00:52:04.476)
  1. 问题直接原因出在SpringCloudPlugin的这个函数里面:
public Boolean skip(final ServerWebExchange exchange) {
        final SoulContext body = exchange.getAttribute(Constants.CONTEXT);
        return !Objects.equals(Objects.requireNonNull(body).getRpcType(), RpcTypeEnum.SPRING_CLOUD.getName());
    }

从上面打印日志知道exchange中body的rpc类型是http,而SpringCloudPlugin要求rpc类型必须是springCloud才能用该插件处理。

  1. 再次分析第4点的日志,发现在经过global插件之后,rpcType参数就变成了http,于是断点进入GlobalPlugin,跟踪到如下函数(org.dromara.soul.plugin.global.DefaultSoulContextBuilder.build(ServerWebExchange)):
public SoulContext build(final ServerWebExchange exchange) {
        final ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();
        MetaData metaData = MetaDataCache.getInstance().obtain(path);
        if (Objects.nonNull(metaData) && metaData.getEnabled()) {
            exchange.getAttributes().put(Constants.META_DATA, metaData);
        }
        return transform(request, metaData);
    }

原来是通过元数据来设置rpcType,进入MetaDataCache.getInstance().obtain(path)进一步查看,

public MetaData obtain(final String path) {
        MetaData metaData = META_DATA_MAP.get(path);
        if (Objects.isNull(metaData)) {
            String key = META_DATA_MAP.keySet().stream().filter(k -> PathMatchUtils.match(k, path)).findFirst().orElse("");
            return META_DATA_MAP.get(key);
        }
        return metaData;
    }
  1. 发现META_DATA_MAP这个map只有一个元素,而且还是dubbo的元数据,想到我之前测跑dubbo用例,元数据和规则之类都还在,于是在admin的元数据管理页面禁用了所以的dubbo元数据,并且点击了同步数据按钮,然后再次发送请求发现map里面还是原来那个dubbo的元数据,于是把又去admin那边把dubbo元数据全删掉,点击同步数据,这次终于可以了,正常返回如下结果:
{
    "id": "5",
    "name": "hello world spring cloud findById"
}

一些疑惑

  1. 禁用元数据似乎没有效果,即使点击了同步也还是不行,删掉之后则可以,是因为数据还没同步到bootstrap还是开关无效?
  2. 只有第一条元数据能起作用?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值