36

我正在尝试使用 Go 读取压缩的 HTTP 响应!但我总是收到以下错误消息:

panic: gzip: invalid header
[...] stack trace [...]

如果我运行 "curl -H "Accept-Encoding: gzip" http://foo.com/ | gunzip -" 我会得到正确的响应。我还用 ngrep 进行了仔细检查,并且 Accept-Encoding/Content-Encoding 对已正确发送/返回。

如果我创建一个包含一些虚拟内容的文件并 gzip 压缩它,我可以从我的 Go 中读取它!程序。

我用于测试的程序:

package main

import (
    "io"
    //"os"
    "fmt"
    "compress/gzip"
    "net/http"
)

func main() {
    /* This works fine
    f, _ := os.Open("/tmp/test.gz")
    defer f.Close()
    reader, err := gzip.NewReader(f)
    */

    // This does not :/
    resp, _ := http.Get("http://foo.com/")
    defer resp.Body.Close()
    reader, err := gzip.NewReader(resp.Body)

    if err != nil { panic(err) }

    buff := make([]byte, 1024)
    for {
        n, err := reader.Read(buff)

        if err != nil && err != io.EOF {
            panic(err)
        }

        if n == 0 {
            break
        }
    }

    s := fmt.Sprintf("%s", buff)
    fmt.Println(s)
}

我忽略了什么吗?

4

4 回答 4

66

编辑:以下是手动处理压缩的示例。如果你不设置header,默认Transport会帮你做,然后在你读取response.Body的时候解压。

client := new(http.Client)

request, err := http.NewRequest("GET", "http://stackoverflow.com", nil)
request.Header.Add("Accept-Encoding", "gzip")

response, err := client.Do(request)
defer response.Body.Close()

// Check that the server actually sent compressed data
var reader io.ReadCloser
switch response.Header.Get("Content-Encoding") {
case "gzip":
    reader, err = gzip.NewReader(response.Body)
    defer reader.Close()
default:
    reader = response.Body
}

io.Copy(os.Stdout, reader) // print html to standard out

为简洁起见,删除了错误处理。我保留了延期。

于 2012-10-30T00:58:22.267 回答
37

net/http#Transport处理gzip压缩响应。你不必做任何特别的事情。

看看这个DisableCompression选项,在这里

于 2012-10-29T22:08:15.590 回答
18

根据net/http 文档(第 110 行),如果您手动设置Accept-Encoding请求标头,那么 gzipped 响应将不会由 http.Transport 自动解压缩。否则,行为由 Transport 的DisableCompression布尔值控制

于 2016-08-15T11:47:49.030 回答
0

以下是手动处理压缩的示例。


import "compress/gzip"

func ReadAll(r io.Reader) ([]byte, error) {
    reader, err := gzip.NewReader(r)
    if err != nil {
        return nil, err
    }
    defer reader.Close()
    buff, err := ioutil.ReadAll(reader)
    return buff, err
}
于 2021-12-07T08:51:35.417 回答