【问题标题】:How to encode jsonb as part of an http response in golang如何将jsonb编码为golang中http响应的一部分
【发布时间】:2016-09-24 06:31:19
【问题描述】:

我很难通过网络移动 json。

在 Postgres 数据库中有一个 jsonb 字段,我需要将其添加到结构中,然后再通过网络将其作为 http 响应发送。

如果结构的有效负载字段是string,则封送处理会像"{\"id\": \"3aa5fff0-ad91-41b1-84f0-d97f38e0e0f4\", \"user\": 1 } 一样转义json。

如果结构的有效负载字段是json.RawMessage,编组会将 json 转义为(我想象的)base64 编码字节序列。

这是我正在编组并写入 http 响应流的结构:

type NestJobReturn struct { Status string `json:"status"` Nest json.RawMessage `json:"nest"` }

我构建了这个结构的ret 实例并将其打印出来。如果我使用%v,它会显示字节,而%s 会将其显示为正确的、未转义的 json 字符串:

log("Value of ret.Nest: %v", ret.Nest) // Value of ret.Nest: [123 34 105 ... log("Value of ret.Nest as a string: %s", ret.Nest) // Value of ret.Nest as a string: {"id": "f053...

编组和 i/o 就这样完成了:

js, _ := json.Marshal(ret) res.Header().Set("Content-Type", "application/json") res.Write(js)

客户端当前收到的整个消息看起来有点像这样:

{"status":"ok","nest":"eyJpZCI6ICJmMD..."}

...但“nest”的预期值是数据库中我的jsonb 列中的有效json。

有什么想法吗?

【问题讨论】:

  • Array and slice values encode as JSON arrays, except that []byte encodes as a base64-encoded string. json.RawMessage 是 []byte 类型

标签: json postgresql go


【解决方案1】:

您需要将嵌套字段定义为pointerjson.RawMessage,例如

type NestJobReturn struct {
    Status string           `json:"status"`
    Nest   *json.RawMessage `json:"nest"`
}

jsonStr := `{"type": "Object", "desc": "Simple nested object"}`
raw := json.RawMessage(jsonStr)

ret := NestJobReturn {
    Status: "DONE",
    Nest:   &raw,
}

一个工作示例https://play.golang.org/p/Ju7kgbawss

【讨论】:

  • 这可行,但the RawMessage exmaple in the official docs 不使用指向 RawMessage 的指针,所以我认为它被设计为用作值。
  • 由于thisthis,我更喜欢使用*json.RawMessage。在将容器 (struct) 传递为 valuepointerjson.Marshal 时,它会给出相同的 JSON 字符串。 Playground
  • 谢谢,这些问题链接非常棒!我理解你的修复为什么有效,但我很难理解为什么我的修复。这对我来说很清楚。
  • 非常感谢!我已经设法以不涉及 RawMessage 的不同方式完全解决了这个问题。但无论如何,这很高兴知道,因为我将来可能需要这样做。
【解决方案2】:

你需要编组指向你的 ret 而不是 ret 本身的指针

只需将
js, _ := json.Marshal(ret)更改为
js, _ := json.Marshal(&ret)

它应该开始工作了。
playground link

更好的是,您可以使用 I Putu Susila's answer 或用这个稍微调整的版本替换 json.RawMessage 来证明您的结构白痴

type RawMessage []byte

// MarshalJSON returns m as the JSON encoding of m.
func (m RawMessage) MarshalJSON() ([]byte, error) {
    return m, nil
}

// UnmarshalJSON sets *m to a copy of data.
func (m *RawMessage) UnmarshalJSON(data []byte) error {
    if m == nil {
        return errors.New("json.RawMessage: UnmarshalJSON on nil pointer")
    }
    *m = append((*m)[0:0], data...)
    return nil
}

那么您的结构将始终正确地编组自身。
playground link

这是the github issue 中针对此怪癖建议的修复(链接由I Putu Susila's comment 提供),但共识是即使这是 RawMessage 应该表现的方式,但他们现在无法更改它,因为go 标准库的兼容性保证。幸运的是,仅仅因为他们无法在标准库中修复它并不意味着您无法在自己的代码库中修复它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-13
    • 2013-09-28
    • 2010-11-15
    • 1970-01-01
    • 2013-08-13
    • 1970-01-01
    • 2018-04-14
    相关资源
    最近更新 更多