使用Go解码gZip格式的json数据

5
作为一个Go的新手,我很难确定问题所在,但希望提供一些事实能够帮到您。
我正在使用返回其“Content-Encoding”为gzip的API。我已经编写了以下内容来对我的响应结构进行编码:
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)

我已经为了简洁起见删除了错误处理,但感兴趣的重点是,如果我取消stdout的打印注释,我会得到预期的结果。然而,解码并没有给我我所期望的结果。有什么指针吗?是不是结构必须完全映射到响应?
以下是完整示例: https://play.golang.org/p/4eCuXxXm3T

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

6

来自文档

如果设置DisableCompression为true,则当请求中没有现有的Accept-Encoding值时,阻止Transport使用“Accept-Encoding:gzip”请求头请求压缩。 如果Transport自己请求gzip并获得gzipped响应,则会在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,可以在这里注册:https://devportal.tescolabs.com/感觉这个应该能够正常工作。 - Sion
看看我的更新代码。我使用了一个JSON转Go工具来修复你的TescoResponse。https://play.golang.org/p/Vt07y_xgak - Ezequiel Moreno
好的,我现在完全被搞糊涂了。我已经在Intellij和Atom中运行了它,并通过调试器逐步执行了它。每次结构体都是空的。我正在运行最新的go go version go1.7 darwin/amd64 - Sion
我已经完全复制了你的代码,并替换了我的API密钥。程序打印Data from response &{[]} - Sion
谢谢@Ezequiel。我完全错过了你对新结构的修改。我很惊讶我们需要将整个响应建模,因为我理解的反序列化是我们可以选择所需的位。无论如何,这是我的理解不够好。感谢您的支持。 - Sion

-1

正如@icza在评论中提到的那样,不需要进行解码,因为使用gzip reader读取时会自动解码。也许可以尝试以下方法:

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

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