在Go中读取gzip压缩的HTTP响应

Jér*_*e R 31 go

我试图用Go读取一个gzipped HTTP响应!但我总是收到以下错误消息:

panic: gzip: invalid header
[...] stack trace [...]
Run Code Online (Sandbox Code Playgroud)

如果我运行"curl -H"接受编码: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)
}
Run Code Online (Sandbox Code Playgroud)

我忽略了什么吗?

Ste*_*erg 53

编辑:以下是手动处理压缩的示例.如果您没有设置标题,默认传输将为您执行此操作,然后在您阅读响应时解压缩.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
Run Code Online (Sandbox Code Playgroud)

为简洁起见,删除了错误处理.我坚持不懈.


sim*_*nke 31

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

  • 但它似乎没有处理`deflate` (3认同)
  • 我投赞成票。标准客户端传输为您处理 gzip。这包括在您从 response.Body 读取数据时自动解压缩数据。OP 的问题是他试图第二次减压。 (2认同)

小智 12

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