apolloconfig / apollo

Apollo is a reliable configuration management system suitable for microservice configuration management scenarios.
https://www.apolloconfig.com
Apache License 2.0
28.95k stars 10.19k forks source link

Spring Cloud Gateway 中配置路由的 metadata 不生效(Map<String, Object> 配置 Number 值,获取到的类型为 String) #4990

Closed oktfolio closed 8 months ago

oktfolio commented 8 months ago

描述bug

在 Spring Cloud Gateway 中配置路由的 metadata,获取到的值为 String,应该是 Number 类型,导致该配置无法生效。

复现

通过如下步骤可以复现:

  1. Spring Cloud Gateway 项目配置 yaml
    spring:
    cloud:
    gateway:
      discovery:
        locator:
          enabled: false
      routes:
      - id: xx
        uri: xxx
        predicates:
        - Path=xxx
        filters:
        - StripPrefix=1
        metadata:
          response-timeout: 1
         # response-timeout: int! 1 也存在这个问题
          connect-timeout: 200
  2. 启动 Spring Cloud Gateway 项目,访问已配置路由的接口,超时时间未生效。

Spring Cloud Gateway 中自动配置的 GatewayProperties#routes 为 RouteDefinition,RouteDefinition 中 metadata 类型为 Map<String, Object>。

而最终通过下面代码获取到的 responseTimeoutAttr 类型是 String,导致该配置无法生效。

private Duration getResponseTimeout(Route route) {
        Object responseTimeoutAttr = route.getMetadata().get(RESPONSE_TIMEOUT_ATTR);
        if (responseTimeoutAttr != null && responseTimeoutAttr instanceof Number) {
            Long routeResponseTimeout = ((Number) responseTimeoutAttr).longValue();
            if (routeResponseTimeout >= 0) {
                return Duration.ofMillis(routeResponseTimeout);
            }
            else {
                return null;
            }
        }
        return properties.getResponseTimeout();
    }

该配置项是通过 DefaultConfig#getProperty(String key, String defaultValue) System.getenv(key) 读取的,这里返回的类型恒为 String。就算使用 !int

根据源码来看,类型为 Map<String, Object>,配置为 String:Number 的应该都会存在这种问题。

期望

对于 ConfigurationProperties 中类型为 Map<String, Object> 的成员,若配置值为 Number,map 中值的类型也应该是 Number。

额外的细节和日志

dosubot[bot] commented 8 months ago

🤖

您遇到的问题是由于Apollo配置管理系统处理元数据的方式。在提供的代码中,元数据存储在Map<String, String>中。这意味着所有的值,无论它们的原始类型是什么,都被存储为字符串。

当您从元数据映射中检索一个值时,它总是会作为一个字符串返回,即使原始值是一个数字。这就是为什么在您的Spring Cloud Gateway路由配置中,数字值被检索为字符串类型。

这是相关的代码:

private Map<String, String> metadata = new HashMap<>(8);

@Override
public Map<String, String> getMetadata() {
  return this.metadata;
}

public void setMetadata(Map<String, String> metadata) {
  this.metadata = metadata;
}

在这段代码中,getMetadata()返回元数据映射,setMetadata(Map<String, String> metadata)设置元数据映射。两个方法都使用Map<String, String>,这意味着所有的值都被视为字符串。

关于如何处理从元数据映射中检索值时的类型转换,我在仓库中没有找到答案,但答案可能在其他地方,或者我可能错过了。

我找到了一个类似的已解决问题,可能对您有所帮助。问题是spring boot集成apollo自定义非String类型转换器转换异常,最后更新于2022年7月20日。建议的解决方案是:为了使自定义转换器与不同的环境兼容,yaml中的数字已经改为字符串配置,自定义转换器的源类型也已经改为String类型进行处理。

如果您有更多的信息或者有其他的问题,欢迎继续提问。

Sources


This response is meant to be useful and save you time. It is not meant to be a precise solution, but rather a starting point for your own research.

Help me be more useful! Please leave a 👍 if this is helpful and 👎 if it is irrelevant.

If you want to continue the conversation, start your reply with @dosu-bot.

oktfolio commented 8 months ago

Same as #2896