【问题标题】:Decoding gZip json with Go使用 Go 解码 gZip json
【发布时间】:2016-08-16 18:27:24
【问题描述】:

作为围棋新手,我很难确定问题所在,但希望提供一些事实会对您有所帮助。

我正在使用一个 API,它将其 Content-Encoding 作为 gzip 返回。我编写了以下代码来编码我的响应结构:

reader, err = gzip.NewReader(resp.Body)
defer reader.Close()

// print to standard out
//_, err = io.Copy(os.Stdout, reader)
//if err != nil {
//  log.Fatal(err)
//}

// Decode the response into our tescoResponse struct
var response TescoResponse
err := json.NewDecoder(reader).Decode(&response)

为简洁起见,我删除了错误处理,但有趣的是,如果我取消对标准输出的打印注释,我会得到预期的结果。但是,解码并没有给我我的期望。任何指针?结构必须精确映射到响应吗??

这是完整的示例: https://play.golang.org/p/4eCuXxXm3T

【问题讨论】:

  • http 包自动解码 gzip 响应。你从resp.Body 得到的是未压缩的响应。无需手动解码。像这样解码:json.NewDecoder(resp.Body).Decode(&response)
  • 这样做会给我错误[NewDecoder]: invalid character '\x1f' looking for beginning of value
  • 如果响应包含Content-Encoding: gzip 标头,net/http 包会自动为您解码。请检查是否存在。
  • 您看过我发布的完整示例吗?其中一个步骤是检查编码。

标签: json go gzip


【解决方案1】:

From the documenation:

DisableCompression,如果为真,则阻止传输请求 压缩时使用“Accept-Encoding: gzip”请求标头 请求不包含现有的 Accept-Encoding 值。如果运输 自己请求 gzip 并获得 gzip 响应,它是 在 Response.Body 中透明地解码。但是,如果用户 明确要求 gzip 它不会自动解压缩。

建议的解决方案:

type gzreadCloser struct {
    *gzip.Reader
    io.Closer
}

func (gz gzreadCloser) Close() error {
    return gz.Closer.Close()
}

// 然后在你的 http 调用中 ....

    if resp.Header.Get("Content-Encoding") == "gzip" {
        resp.Header.Del("Content-Length")
        zr, err := gzip.NewReader(resp.Body)
        if err != nil {
            return nil, err
        }
        resp.Body = gzreadCloser{zr, resp.Body}
    }

// then you will be able to decode the json transparently

if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {

}

根据您的代码改编的解决方案:https://play.golang.org/p/Vt07y_xgak

【讨论】:

  • 抱歉延迟回复。我尝试了您建议的代码,但不幸的是我仍然得到一个空结构。如果你想自己尝试这个 api,你可以在这里注册; devportal.tescolabs.com 这感觉真的应该管用。
  • 查看我更新的代码。我已经使用 JSON to Go 工具修复了您的 TescoResponse。 play.golang.org/p/Vt07y_xgak
  • 好吧,我现在完全糊涂了。我已经在 Intellij 和 Atom 中运行了它,并逐步通过了调试器。结构每次都是空的。我正在运行最新的 go go version go1.7 darwin/amd64
  • 我已经完全复制了您的代码并替换了我的 api 密钥。程序打印Data from response &{[]}
  • 谢谢@Ezequiel。我完全错过了你对新结构的改动。我很惊讶地看到我们需要对完整的响应进行建模,因为我对 unmarshal 的理解是我们可以选择我们想要的位。无论哪种方式,我的理解都很差。感谢您的支持
【解决方案2】:

正如@icza 在 cmets 中提到的,不需要解码,因为 gzip 阅读器会在您阅读时自动解码。也许试试:

ubs := make([]byte, len) // check Content-Length header to set len
n, err := reader.Read(ubs)
err := json.Unmarshal(ubs, &response)

【讨论】:

    猜你喜欢
    • 2018-05-05
    • 1970-01-01
    • 2019-05-19
    • 2015-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-24
    相关资源
    最近更新 更多