GO中的必要护理:如何安全地使用元帅()和umarshal()功能
#初学者 #编程 #braziliandevs #go

最近,我的团队的技术负责人发现了一个涉及**Unhmarshal()**的错误,他向我们展示了发生了什么事,我们一直在谈论发生的事情的风险。这最终使我很感兴趣,我最终研究了更多关于以Go进行操纵JSON时要接受适当护理的情况。

因此,让我们开始谈论 Marshal() Unmarshal() 的功能是什么关心。我们走吧?

Manipulaã§o nativa do json em go:元帅emarshal

当涉及到GO程序语言中JSON格式数据的操纵时,函数 Marshal() Unmarshal() 是是是允许对话的强大工具在JSON和A struct 中的JSON中的A struct (或对象)之间。但是,重要的是要了解与这些操作相关的潜在危险,并采用一些实践以避免微妙的错误,这可以节省您几个小时的错误调试。

错误1:忘记导出字段

从常见错误开始,这个问题很容易解决,但是如果您不小心,您可以努力寻找。请记住,如果第一个字母是薄荷或女仆,则可以使用变量,功能,运动或字段的隐私工作,表明它是私有的或Pi。好吧,当使用 Marshal() Unmarshal() 时,请记住,只有出口领域,即在序列化(将对象/struct转换为JSON)中不包含字段,或者在应有的期间填充零值(将JSON转换为对象/struct。

很好,让我们在这种情况下评估简单的错误,美吗?我们有用户对象,其中有两个字段: namefusuario 密码,一个被欺负,另一个是私人的。因此,在尝试序列化时,JSON将没有密码字段,当我们希望时,我们可以看到密码字段未完成:

error_campo_nao_exported.go:

package main

import (
    "encoding/json"
    "fmt"
)

type Usuario struct {
    NomeDeUsuario string `json:"nome_de_usuario"`
    senha         string `json:"senha"` // campo não exportado
}

func main() {
    // Caso de serialização
    jose := Usuario{NomeDeUsuario: "jose", senha: "senha-do-jose"}
    stringJson, errMarshal := json.Marshal(jose) // O campo 'senha' não será incluído por conta que ele é privado
    if errMarshal != nil {
        fmt.Println(errMarshal.Error())
        panic(errMarshal)
    }
    fmt.Println("json do jose: " + string(stringJson))

    // Caso de desserialização
    var maria Usuario
    jsonMaria := []byte("{\"nome_de_usuario\":\"maria\", \"senha\":\"senha-de-maria\"}")
    errUnamarshal := json.Unmarshal(jsonMaria, &maria)
    if errUnamarshal != nil {
        fmt.Println(errUnamarshal.Error())
        panic(errUnamarshal)
    }
    fmt.Println(fmt.Sprintf("struc de maria: %+v", maria))
}

运行koud7命令时,我们可以在控制台上看到以下内容:

json do jose: {"nome_de_usuario":"jose"}
struc de maria: {NomeDeUsuario:maria senha:}

娱乐以避免几分钟,在©小时内试图看,因为它没有保存某个字段,我们将始终确保仅出口应提供的字段。

solory_erro_campo_nao_nao_exported.go:

package main

import (
    "encoding/json"
    "fmt"
)

type Usuario struct {
    NomeDeUsuario string `json:"nome_de_usuario"`
    Senha         string `json:"senha"` // campo não exportado
}

func main() {
    // Caso de serialização
    jose := Usuario{NomeDeUsuario: "jose", Senha: "senha-do-jose"}
    stringJson, errMarshal := json.Marshal(jose) // O campo 'senha' não será incluído por conta que ele é privado
    if errMarshal != nil {
        fmt.Println(errMarshal.Error())
        panic(errMarshal)
    }
    fmt.Println("json do jose: " + string(stringJson))

    // Caso de desserialização
    var maria Usuario
    jsonMaria := []byte("{\"nome_de_usuario\":\"maria\", \"senha\":\"senha-de-maria\"}")
    errUnamarshal := json.Unmarshal(jsonMaria, &maria)
    if errUnamarshal != nil {
        fmt.Println(errUnamarshal.Error())
        panic(errUnamarshal)
    }
    fmt.Println(fmt.Sprintf("struc de maria: %+v", maria))
}

执行解决方案时,我们将有以下内容:

json do jose: {"nome_de_usuario":"jose"}
struc de maria: {NomeDeUsuario:maria senha:}

错误2:未验证输入数据到umarshal()

好吧,第二个错误是我最近看到的,当时我想起了很长一段时间,在巴哈尔·沙阿(Bahar Shah)的文章中:认为他们做。标题是非常自言自语的,并且在 Unmarshal() 中完全有意义,返回的错误只有当JSON形成不佳的情况下,它不会验证字段。因此,如果您收到任何JSON,即使它没有结构的字段,输出也是成功的,这意味着没有错误,但是其对象/支柱不会完成任何值。

进入函数之前的入口 Unmarshal() ,重要的是,我们必须验证输入数据以避免来自JSON的错误。要进行验证,旅途中有一些实践,例如:您可以创建自己的100%验证的基础,或者可以使用软件包验证器创建验证,我们将无法使用一种方法来促进验证简化如何声明以及如何验证。让我们使用验证器来示例,因为它是一个可以在更完整的,美容的东西中扩展的解决方案?

我们的方式收到包含狗信息的JSON,对吗?在此验证中,我们的对象有3个字段:名称 age ehamigavel 每个人都有自己的验证。例如,他是义务(******************** 必需 ***** ** ************ ),需要在母亲3个字符和母亲12个字符( ******** * min = 3,max = 12 ********* )是一个数字( *************** 数字 ******************)和最后,Ehamivavel只是义务。现在,我们想象我们无意中收到狗数据,但缺少一个领域。在这种情况下,使用验证,我们将避免保存不完整的数据NUAM基础。让我们以错误的方式查看以下方式:

error_nao_validando_campos.go:

package main

import (
    "encoding/json"
    "errors"
    "fmt"
    "github.com/go-playground/validator/v10"
)

type Cachorro struct {
    Nome       string `json:"nome" validate:"required,min=3,max=12"`
    Idade      int    `json:"idade" validate:"required,numeric"`
    EhAmigavel bool   `json:"eh_amigavel" validate:"required"`
}

type ErrosDeValidacao struct {
    Campo string
    Tag   string
    Valor string
}

var Validator = validator.New()

func validaCachorro(cachorro Cachorro) []ErrosDeValidacao {
    erros := make([]ErrosDeValidacao, 0)

    err := Validator.Struct(cachorro)
    if err != nil {
        for _, erroValidator := range err.(validator.ValidationErrors) {
            erro := ErrosDeValidacao{
                Campo: erroValidator.Field(),
                Tag:   erroValidator.Tag(),
                Valor: erroValidator.Param(),
            }
            erros = append(erros, erro)
        }
        return erros
    }
    return nil
}

func main() {
    jsonCachorro := []byte("{\"nome\":\"bilu\", \"idade\":5}")
    var cachorro Cachorro
    errUnamarshal := json.Unmarshal(jsonCachorro, &cachorro)
    if errUnamarshal != nil {
        fmt.Println(errUnamarshal.Error())
        panic(errUnamarshal)
    }

    errosValidacao := validaCachorro(cachorro)
    if len(errosValidacao) > 0 {
        fmt.Println(fmt.Sprintf("erros: %+v", errosValidacao))
        panic(errors.New("erro ao validar o json do cachorro"))
    }

    fmt.Println(fmt.Sprintf("cachorro: %+v", cachorro))
}

使用go run erro_nao_validando_campos.go执行代码时,我们有以下内容:

erros: [{Campo:EhAmigavel Tag:required Valor:}]
panic: erro ao validar o json do cachorro

goroutine 1 [running]:
main.main()
        caminho/para/seu/codigo/erro_nao_validando_campos.go:54
exit status 2

现在,如果我们以相同的方式执行,则在JSON中进行以下校正:

jsonCachorro := []byte("{\"nome\":\"bilu\", \"idade\":5, \"eh_amigavel\":true}")

并再次运行,我们的输出将如下以下,表明验证有效并将阻止错误的数据:

cachorro: {Nome:bilu Idade:5 EhAmigavel:true}

错误3:制作元帅时的无限循环!

现在可能发生的错误,如果您必须处理代码中的循环引用(顺便说一句,非常具体的是,如何操纵双子妇)是无限循环时,当调用函数 Marshal() < /strong>或 Unmarshal() ,这可能导致程序崩溃或导致过度资源消耗。

所以,也许您试图想象一个场景会发生吗?好吧,我将简化我可以的母亲:我想象一下您正在做社交网络的风景,您需要从玛丽亚(Maria)返回玛丽亚(Maria),后者在朋友名单上有约翰(John)。因此,您在数据库中查找了玛丽亚和约翰的数据,现在将填补他们的友谊关系,后来将转换代表玛丽亚的对象,将代表玛丽亚变成一个字节的blyte(字节阵列确实可以使用),以便能够将其归还给您的API ,该GO将将此数据转换为端点响应字符串。如果您在此对话中感到困惑,从对象到从字节返回到API中的slice,请担心另一篇文章会解释有关。

好吧,让我们以以下错误

来示例

rede_social_loop_infinito_marshal.go:

package main

import (
    "encoding/json"
    "fmt"
)

type Pessoa struct {
    Nome   string    `json:"nome"`
    Amigos []*Pessoa `json:"amigos"`
}

func main() {
    maria := &Pessoa{Nome: "Maria"}
    joao := &Pessoa{Nome: "João"}
    maria.Amigos = []*Pessoa{joao}
    joao.Amigos = []*Pessoa{maria}

    data, err := json.Marshal(maria) // Pode entrar em um ciclo infinito aqui oh!
    if err != nil {
        fmt.Println(err.Error())
        panic(err)
    }
    fmt.Println(string(data))
}

用Koud13执行上述操作时,让我们看看GO准备检测此循环,然后将其返回给我们的错误。输出将是这样的:

json: unsupported value: encountered a cycle via *main.Pessoa
panic: json: unsupported value: encountered a cycle via *main.Pessoa

goroutine 1 [running]:
main.main()
        caminho/para/seu/codigo/rede_social_loop_infinito_marshal.go:22
exit status 2

好吧,现在让我们解决我们产生的问题!为了解决这个问题,我们可以通过两种方式做。首先是要求在JSON中忽略该领域,我们在该领域的声明中使用 json:"-" 而不是 json:"amigos" 。但这会让我们发送朋友列表,我们想发送,对吗?好吧,让我们解决其他方面的问题,它正在使用中间格式进行序列化。通常,这种格式将更简化。让我们去下面的路。

solution_rede_social_loop_infinito_marshal.go:

package main

import (
    "encoding/json"
    "fmt"
)

type Pessoa struct {
    Nome   string    `json:"nome"`
    Amigos []*Pessoa `json:"amigos"`
}

type PessoaSerializavel struct {
    Nome   string   `json:"nome"`
    Amigos []string `json:"amigos"`
}

func convertaParaPessoaSerializavel(pessoa *Pessoa) PessoaSerializavel {
    amigosSerializaveis := make([]string, len(pessoa.Amigos))

    for indice, amigo := range pessoa.Amigos {
        amigosSerializaveis[indice] = amigo.Nome
    }

    return PessoaSerializavel{
        Nome:   pessoa.Nome,
        Amigos: amigosSerializaveis,
    }
}

func main() {
    maria := &Pessoa{Nome: "Maria"}
    joao := &Pessoa{Nome: "João"}
    maria.Amigos = []*Pessoa{joao}
    joao.Amigos = []*Pessoa{maria}

    data, err := json.Marshal(convertaParaPessoaSerializavel(maria)) // agora aqui não dará mais erro de loop
    if err != nil {
        fmt.Println(err.Error())
        panic(err)
    }

    fmt.Println(string(data))
}

当我们使用go run solucao_rede_social_loop_infinito_marshal.go执行方式时,这里的解决方案效果很好。我知道这是一种方式,我们可以避免使用这个问题,但这就是我认为分析此错误的最简单方法。它仅仅是nicnic,我希望它设法通过了错误以及如何纠正它。

总结了£o

好吧,我们已经结束了本文的结尾!开始阅读 100 GO混合后,带有错误和纠正方式,以及如何避免它们 本书的作者开始带来错误和妈妈的道路,然后带来我提出的这些案例的解决方案,我决定尝试使用更基本的一些模型以了解其工作原理,希望您喜欢!

现在,实际上,功能 Marshal() Unmarshal() 在与JSON合作时是至关重要的资源,但是需要具体的护理以确保您的方式有效,安全且错误。意识到潜在的危险,并遵循我在这里评论的一些实践,您可以有效地使用这些功能,而无需担心。

但永远记住,可以(并且应该)有我在这里没有评论的其他错误,始终应始终咨询 documentação oficial do pacote koude19 以获取有关正确使用这些功能的详细信息,例如一如既往地练习并与计划的其他人进行交谈。

反思