alibaba / spring-cloud-alibaba

Spring Cloud Alibaba provides a one-stop solution for application development for the distributed solutions of Alibaba middleware.
https://sca.aliyun.com
Apache License 2.0
27.96k stars 8.34k forks source link

Nacos Config NacosPropertySourceBuilder parse error #2857

Closed Xyk859852 closed 2 years ago

Xyk859852 commented 2 years ago

When using SpringCloudAlibaba, Nacos configuration center, using sharedConfigs or extensionConfigs to load the configuration, when the configuration is in JsonArray format, is there any exception when the configuration is refreshed? For example, can the parse object only be a JsonObject Object not a JSONArray??

The corresponding version is SpringCloudAlibaba: 2021.0.1.0 SpringCloud: 2021.0.1, SpringBoot: 2.6.8

yuhuangbin commented 2 years ago

Can you provide details? Eg: configuration content, error stack information.

Xyk859852 commented 2 years ago

configuration content : [ { "filters": [{ "name":"RewritePath", "args":{ "regexp":"/system-web-app/(?.*)", "replacement":"/${segment}" } }], "id": "system-web-app", "order": 0, "predicates": [{ "args": { "pattern": "/system-web-app/**" }, "name": "Path" }], "uri": "lb://system-web-app" }, { "filters": [], "id": "baidu_route", "order": 1, "predicates": [{ "args": { "pattern": "/blibli-1" }, "name": "Path" }], "uri": "https://www.bilibili.com/" } ] error stack information image

image

Xyk859852 commented 2 years ago
image

From the source code here, it can only be resolved JsonObject

yuhuangbin commented 2 years ago

Your application scenario should be dynamic routing. You can refer:

  @Autowired
  private NacosConfigManager nacosConfigManager;

  @Autowired
  private RouteDefinitionWriter routeDefinitionWriter;

  @Autowired
  private ApplicationEventPublisher publisher;

  public void refreshRoutes(String configInfo) {
   String config = nacosConfigManager.getConfigService().getConfig(dataId, group, 5000);
   List<RouteDefinition> routeDefinitions = covertoRouteDefinition(configInfo);
   modifyRoutes(routeDefinitions);
   this.publisher.publishEvent(new RefreshRoutesEvent(this));
  }

  private void modifyRoutes(List<RouteDefinition> routeDefinitions) {
          routeDefinitions.forEach(routeDefinition -> routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe());
  }
Xyk859852 commented 2 years ago

I try

Xyk859852 commented 2 years ago

Using the method you provided, there will still be a problem and the existing error reporting problem will not be solved

image image image
yuhuangbin commented 2 years ago

Your application scenario should be dynamic routing. You can refer:

  @Autowired
  private NacosConfigManager nacosConfigManager;

  @Autowired
  private RouteDefinitionWriter routeDefinitionWriter;

  @Autowired
  private ApplicationEventPublisher publisher;

  public void refreshRoutes(String configInfo) {
   String config = nacosConfigManager.getConfigService().getConfig(dataId, group, 5000);
   List<RouteDefinition> routeDefinitions = covertoRouteDefinition(configInfo);
   modifyRoutes(routeDefinitions);
   this.publisher.publishEvent(new RefreshRoutesEvent(this));
  }

  private void modifyRoutes(List<RouteDefinition> routeDefinitions) {
          routeDefinitions.forEach(routeDefinition -> routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe());
  }

File separate configuration. eg:

dynamic-route.data-id=xxx.json
dynamic-route.group=DEFAULT
Xyk859852 commented 2 years ago
image image
yuhuangbin commented 2 years ago

You need to pull the configuration information through ConfigService and write it through routeDefinitionWriter#save

Xyk859852 commented 2 years ago

This is what I did. My route reads and writes are OK, but there is a problem when Nacos is refreshed at the end. I understand that it has nothing to do with the Gateway route

Xyk859852 commented 2 years ago

The piece of code that my Nacos listens to is fine, but there is a problem with the last Nacos refresh itself

yuhuangbin commented 2 years ago

Don't use onfiguration Item spring.cloud.nacos.config.shared-configs. You can use ConfigService to pull configuration from nacos.

ruansheng8 commented 2 years ago

它实际上是通过这个JSON对象从根路径一层层解析成为properties格式的key , 如果是数组类型,那么就没有根节点了.

如果是要做网关路由动态发布的话,可以生成这样的格式

{
    "spring":
    {
        "cloud":
        {
            "gateway":
            {
                "routes":
                [
                  // 路由配置...
                ]
            }
        }
    }
}

网关层只需监听这个配置 , Spring Cloud Gateway 官方的 PropertiesRouteDefinitionLocator 会自动实时加载路由变更 , 因为上面这个格式的JSON被解析后对应的yaml就是

spring:
  cloud:
    gateway:
      routes:
        - 路由配置...

使用该方式需要注意Nacos上是否已经有其他配置文件也配置了 "spring.cloud.gateway.routes" (会相互覆盖) , 解决方案也比较简单 , 监听对应的配置文件 , 参考

@Component
public class CustomPropertiesRouteDefinitionLocator implements RouteDefinitionLocator {

    private final Environment environment;

    public CustomPropertiesRouteDefinitionLocator(Environment environment) {
        this.environment = environment;
    }

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        List<RouteDefinition> routes = Binder.get(this.environment)
                .bindOrCreate("spring.cloud.gateway.custom-routes", GatewayProperties.class)
                .getRoutes();
        return Flux.fromIterable(routes);
    }
}