最近,我的团队的技术负责人发现了一个涉及**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 以获取有关正确使用这些功能的详细信息,例如一如既往地练习并与计划的其他人进行交谈。
反思
- Donovan,A。A.和Kernighan,B。W.(2016)。程序语言GO。NovatecEditora。
- 编码/JSON软件包。一次性销售:https://pkg.go.dev/encoding/json。
- stackoverflow。 disponãvelem:https://stackoverflow.com/questions/32708717/go-when-will-json-unmarshal-to-struct-return-error
- Artigo Medium de Bahar Shah- go to to to n bahar shah to n of shalshal错误可能无法像您认为他们这样做那样奏效。 disponãvelem:https://baharbshah.medium.com/gos-unmarshal-errors-might-not-work-the-way-you-think-they-do-949f8fe15a09
- 验证程序包页面。与:https://pkg.go.dev/github.com/go-playground/validator/v10相关