Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LoadFromYamlBytes 方法导致带有 YAML 标签的结构体解析失败(LoadFromYamlBytes Function Causes Parsing Failures for Structs with YAML Tags) #4152

Open
laopoom opened this issue May 14, 2024 · 2 comments

Comments

@laopoom
Copy link

laopoom commented May 14, 2024

描述: (English version at the end)

go-zero 中的 LoadFromYamlBytes 方法在处理带有 YAML 标签的结构体时会导致解析失败。问题的根源在于该方法先将 YAML 数据转换为 JSON,然后再尝试将 JSON 加载到结构体中。这种中间转换会导致 YAML 标签和结构体字段之间的不匹配,从而导致解析失败。

相关函数:

func LoadFromYamlBytes(content []byte, v any) error {
    b, err := encoding.YamlToJson(content)
    if err != nil {
        return err
    }

    return LoadFromJsonBytes(b, v)
}

这里使用的 YamlToJson 函数将 YAML 数据转换为 JSON 表示,然后再将其解码到结构体中:

func YamlToJson(data []byte) ([]byte, error) {
    var val any
    if err := yaml.Unmarshal(data, &val); err != nil {
        return nil, err
    }

    return encodeToJSON(toStringKeyMap(val))
}

示例:

考虑以下 Go 语言中的结构体定义:

type Config struct {
    rest.RestConf
    Mysql struct {
        Host     string `yaml:"host"`
        Port     int    `yaml:"port"`
        Username string
        Password string
        Database string
    }
}

以及对应的 YAML 配置文件:

Name: myserver
Host: 0.0.0.0
Port: 8888
Mysql:
  host: 127.0.0.1
  port: 13306
  Username: root
  Password: pwd
  Database: data1

在这种情况下,由于 YamlToJson 函数的转换方式,Mysql 下的 host 和 port 字段将无法正确解析。

影响:

此问题会导致意外行为,并且在调试配置问题时带来困难,特别是在从 YAML 配置迁移到 go-zero 时。

建议的解决方案:

为避免此问题,LoadFromYamlBytes 方法应直接将 YAML 内容反序列化到结构体中,而不进行中间的 JSON 转换。这样可以确保 YAML 标签得到正确解析。

建议实现:

// LoadFromYamlBytes 从 YAML 字节内容中加载配置到 v。
func LoadFromYamlBytes(content []byte, v any) error {
    return yaml.Unmarshal(content, v)
}

这种方法保持了 YAML 标签的完整性,确保配置能被正确解析。

感谢考虑这个问题。如需进一步信息,请告诉我。

环境:

go-zero 版本: [github.com/zeromicro/go-zero v1.6.5]
Go 版本: [go version go1.20.5 windows/amd64]

==========================================================================

Description:

The LoadFromYamlBytes function in go-zero can cause parsing failures for structs that use YAML tags. The issue arises because the function first converts the YAML data into JSON, and then attempts to load the JSON into the struct. This intermediate conversion can lead to mismatches between the YAML tags and the struct fields, resulting in failed parsing.

Function in Question:

// LoadFromYamlBytes loads config into v from content yaml bytes.
func LoadFromYamlBytes(content []byte, v any) error {
    b, err := encoding.YamlToJson(content)
    if err != nil {
        return err
    }

    return LoadFromJsonBytes(b, v)
}

The YamlToJson function used here converts the YAML data to JSON representation before decoding it into the struct:

// YamlToJson converts YAML data into its JSON representation.
func YamlToJson(data []byte) ([]byte, error) {
    var val any
    if err := yaml.Unmarshal(data, &val); err != nil {
        return nil, err
    }

    return encodeToJSON(toStringKeyMap(val))
}

Example:

Consider the following struct definition in Go:

type Config struct {
    rest.RestConf
    Mysql struct {
        Host     string `yaml:"host"`
        Port     int    `yaml:"port"`
        Username string
        Password string
        Database string
    }
}

And the corresponding YAML configuration file:

Name: myserver
Host: 0.0.0.0
Port: 8888
Mysql:
  host: 127.0.0.1
  port: 13306
  Username: root
  Password: pwd
  Database: data1

In this scenario, the host and port fields under Mysql will fail to parse correctly because the YamlToJson function will convert them in a way that doesn't respect the YAML tags.

Impact:

This issue can lead to unexpected behavior and difficulties in debugging configuration issues, especially when migrating from YAML-based configurations to go-zero.

Suggested Fix:

To avoid this problem, the LoadFromYamlBytes function should directly unmarshal the YAML content into the struct without converting it to JSON. This ensures that the YAML tags are correctly respected and parsed.

Proposed Implementation:

// LoadFromYamlBytes loads config into v from content yaml bytes.
func LoadFromYamlBytes(content []byte, v any) error {
    return yaml.Unmarshal(content, v)
}

This approach maintains the integrity of YAML tags and ensures accurate parsing of the configuration.

Thank you for considering this issue. Please let me know if any further information is needed.

Environment:

go-zero version: [github.com/zeromicro/go-zero v1.6.5]
Go version: [go version go1.20.5 windows/amd64]

@kevwan
Copy link
Contributor

kevwan commented May 15, 2024

Use json tag.

json tag is also working for yaml, toml.

@laopoom
Copy link
Author

laopoom commented May 15, 2024

Use json tag.

json tag is also working for yaml, toml.

感谢回复。这么设计是为了统一使用 json 标签吗?这样的确有助于简化标签的使用,统一标签格式。不过,这种设计是否会给用户带来一些困扰呢?毕竟在处理 YAML 或者其他非json配置文件时,go代码却需求使用 json 标签可能会让人感到有些迷惑。

==================================================================================

Thank you for your reply. Is this design intended to unify the use of the json tag? It does help to simplify and standardize tag usage. However, could this design cause some confusion for users? After all, it might be a bit perplexing to use json tags when dealing with YAML or others configuration files.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants