将Golang JSON Unmarshal到字段,但不要编组为JSON响应

3
我希望能够访问一个由JSON解封(unmarshal)而来的结构体字段,但是我又想在该结构体被编组(marshaled)时隐藏该字段。
举个例子:
type MyStruct struct {
    GoodField string `json:"goodField"`
    SecretField string `json:"secret"`
}

收到的JSON数据将被反序列化,可以访问secret字段。在服务器响应中使用相同的MyStruct,但是需要隐藏secret字段。

我尝试过使用omitempty-标签,但未生效。

4个回答

3

你在使用 omitempty 方面是正确的,你只需要将 SecretField 设置为 "" 就可以生效。

package main

import (
    "fmt"
    "encoding/json"
)

type MyStruct struct {
    GoodField string `json:"goodField"`
    SecretField string `json:"secret,omitempty"`
}

func main() {

    data := MyStruct{}

    s := `{"goodField": "xxx", "secret": "yyy"}`

    json.Unmarshal([]byte(s), &data);

    fmt.Println(data.GoodField, data.SecretField);

    data.SecretField = ""

    response, _ := json.Marshal(data)

    fmt.Println(string(response))

}

哇,我没有想到这个!只需要在使用完字段后“重置”它...然后omitempty就会像往常一样发挥作用...谢谢! - needmorehalp

2
一般来说,我认为最好的模式是使用单独的请求和响应类型,而不是只是为了防止它被编组而改变数据;那是一种侵入性和破坏性的方法,副作用可能会适得其反。与 Go 的格言“少量重复代码比少量依赖好”一致,最好将这些关注点分开处理,而不是试图让一个类型具有双重功能。
如果你愿意尝试,你可以使用结构体嵌入来DRY(不重复原则)出字段声明。通过 omitempty- json 标记的组合,可以获得所需的结果:
type payload struct {
    A string `json:"a"`
    B string `json:"b,omitempty"`
}

type request struct {
    payload
}

type response struct {
    payload
    B string `json:"-"`
}

这里是上述问题的实际示例
需要注意的是,它并不是没有自己的问题--这里有两个名为B的字段,而不是一个。如果您只使用点运算符字段访问(如我的示例),则可以正常工作。如果您使用结构字面量,则必须小心不要将值放在错误的位置。最好为这些类型编写构造函数,以集中处理该问题并确保正确性。

1
此外,如果你需要让这个字段只能从这个包中访问(这有助于你完全控制对它的访问),你可以使用第一个小写字母使其成为未导出。在所有操作中都应使用此结构,除了编组/解组操作。
type MyStruct struct {
    GoodField string `json:"goodField"`
    secretField string `json:"secret"`
}

再创建一个结构体,仅用于编组。


我也发现了这个功能,但是由于它没有被导出,当反序列化时该字段会被忽略。在我的情况下,我需要访问该字段,但不能在响应中返回。 - needmorehalp
是的,除了un/marshal操作之外,您可以使用此结构。对于这些操作,请使用另一个具有导出字段的类似结构。 - Eugene Lisitsky

0

如果您不能或不想将字段设置为空,您也可以通过自定义编组程序来实现:

type MyStruct struct {
    GoodField   string `json:"goodField"`
    SecretField string `json:"secret"`
}

func (ms *MyStruct) MarshalJSON() ([]byte, error) {
    type MyStructWithoutSecretFields struct {
        GoodField   string `json:"goodField"`
    }
    noSecrets := MyStructWithoutSecretFields{
        GoodField: ms.GoodField,
    }
    return json.Marshal(noSecrets)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接