Decoding gZip json with Go

huangapple go评论208阅读模式
英文:

Decoding gZip json with Go

问题

作为一个Go的新手,很难确定问题的具体位置,但希望给你一些事实会有所帮助。

我正在使用一个返回Content-Encoding为gzip的API。我已经编写了以下代码来对我的响应结构进行编码:

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

// 打印到标准输出
//_, err = io.Copy(os.Stdout, reader)
//if err != nil {
//	log.Fatal(err)
//}

// 将响应解码为我们的tescoResponse结构
var response TescoResponse
err := json.NewDecoder(reader).Decode(&response)

为了简洁起见,我删除了错误处理部分,但值得注意的是,如果我取消注释打印到标准输出的部分,我会得到预期的结果。然而,解码部分却没有给我期望的结果。有什么指导意见吗?是不是结构体必须与响应完全匹配?

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

英文:

As a Go newbie it's difficult for me to pinpoint the problem area, but hopefully giving you some facts will help.

I'm playing with an API which returns its Content-Encoding as gzip. I have written the following to encode my response struct:

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)

I've removed the error handling for brevity, but the point of interest is that if I uncomment the print to stdout, I get the expected result. However, the decode doesn't give me what I expect. Any pointers? Is it that the struct has to map exactly to the response??

Here's the full example:
https://play.golang.org/p/4eCuXxXm3T

答案1

得分: 6

【从文档中】:

> 如果DisableCompression为true,则在请求中不包含现有的Accept-Encoding值时,阻止Transport使用"Accept-Encoding: gzip"请求头请求压缩。如果Transport自行请求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}
}

// 然后你就可以透明地解码json了

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

}

从你的代码中改编的解决方案:https://play.golang.org/p/Vt07y_xgak

英文:

From the documenation:

> DisableCompression, if true, prevents the Transport from requesting
> compression with an "Accept-Encoding: gzip" request header when the
> Request contains no existing Accept-Encoding value. If the Transport
> requests gzip on its own and gets a gzipped response, it's
> transparently decoded in the Response.Body. However, if the user
> explicitly requested gzip it is not automatically uncompressed.

Proposed solution:

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

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

// then in your http call ....

	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 {

}

Adapted solution from your code: https://play.golang.org/p/Vt07y_xgak

答案2

得分: -1

如@icza在评论中提到的,不需要解码,因为gzip读取器在读取时会自动解码。可以尝试以下代码:

ubs := make([]byte, len) // 根据Content-Length头部设置len
n, err := reader.Read(ubs)
err := json.Unmarshal(ubs, &response)
英文:

As @icza mentioned in the comments, decoding isn't required because the gzip reader automatically decodes when you read using it. Perhaps try:

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

huangapple
  • 本文由 发表于 2016年8月17日 02:27:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/38982020.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定