英文:
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
英文:
> 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)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论