gzip 压缩到 http responseWriter

我是 Go 新手。但是我在玩 REST Api。在我拥有的两个函数中,我无法从 json.Marshal 中获得与 json.Encoder 相同的行为


我想用这个函数压缩我的回复:


func gzipFast(a *[]byte) []byte {

    var b bytes.Buffer

    gz := gzip.NewWriter(&b)

    defer gz.Close()

    if _, err := gz.Write(*a); err != nil {

        panic(err)

    }

    return b.Bytes()

}

但是这个函数返回这个:


curl http://localhost:8081/compressedget --compressed --verbose

*   Trying 127.0.0.1...

* Connected to localhost (127.0.0.1) port 8081 (#0)

> GET /compressedget HTTP/1.1

> Host: localhost:8081

> User-Agent: curl/7.47.0

> Accept: */*

> Accept-Encoding: deflate, gzip

< HTTP/1.1 200 OK

< Content-Encoding: gzip

< Content-Type: application/json

< Date: Wed, 24 Aug 2016 00:59:38 GMT

< Content-Length: 30

* Connection #0 to host localhost left intact

这是go函数:


func CompressedGet(w http.ResponseWriter, r *http.Request, ps  httprouter.Params) {


    box := Box{Width: 10, Height: 20, Color: "gree", Open: false}

    box.ars = make([]int, 100)

    for i := range box.ars {

        box.ars[i] = i

    }

    //fmt.Println(r.Header.Get("Content-Encoding"))


    w.Header().Set("Content-Type", "application/json")

    w.Header().Set("Content-Encoding", "gzip")

    b, _ := json.Marshal(box)

    //fmt.Println(len(b))

    //fmt.Println(len(gzipFast(&b)))


    fmt.Fprint(w, gzipFast(&b))

    //fmt.Println(len(gzipSlow(b)))

    //gz := gzip.NewWriter(w)

    //defer gz.Close()

    //json.NewEncoder(gz).Encode(box)

    r.Body.Close()


}

但是当我取消评论时:


//gz := gzip.NewWriter(w)

//defer gz.Close()

//json.NewEncoder(gz).Encode(box)

它工作正常。


牧羊人nacy
浏览 163回答 3
3回答

心有法竹

您需要在访问底层字节之前刷新或关闭您的 gzip 编写器,例如func gzipFast(a *[]byte) []byte {&nbsp; &nbsp; var b bytes.Buffer&nbsp; &nbsp; gz := gzip.NewWriter(&b)&nbsp; &nbsp; if _, err := gz.Write(*a); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; gz.Close()&nbsp; &nbsp; &nbsp; &nbsp; panic(err)&nbsp; &nbsp; }&nbsp; &nbsp; gz.Close()&nbsp; &nbsp; return b.Bytes()}否则,gzip writer 中的缓冲区,但尚未写入最终流的内容不会被收集起来。

凤凰求蛊

我认为问题在于使用fmt.Fprint(w, gzipFast(&b)).如果您查看 gzipFast 的定义,它会返回一个[]byte. 您正在将此切片放入 print 函数中,该函数将所有内容“打印”到w.如果你看一下 io.Writer 的定义:type Writer interface {&nbsp; &nbsp; &nbsp; &nbsp; Write(p []byte) (n int, err error) }您会看到作者可以将其[]byte作为输入进行处理。而不是fmt.Fprint(w, gzipFast(&b))你应该使用w.Write(gzipFast(&b)). 然后你不需要取消注释://gz := gzip.NewWriter(w)//defer gz.Close()//json.NewEncoder(gz).Encode(box)一切都是一个小例子,它显示了代码中发生的事情:https://play.golang.org/p/6rzqLWTGiI

holdtom

我会避免[]byte手动压缩。您可以轻松地使用标准库中现有的编写器。另外,看看compress/flate我认为应该使用哪个而不是 gzip。package mainimport (&nbsp; &nbsp; "net/http"&nbsp; &nbsp; "encoding/json"&nbsp; &nbsp; "compress/gzip"&nbsp; &nbsp; "log")type Box struct {&nbsp; &nbsp; Width int `json:"width"`}func writeJsonResponseCompressed(w http.ResponseWriter, r *http.Request) {&nbsp; &nbsp; box := &Box{Width: 10}&nbsp; &nbsp; w.Header().Set("Content-Type", "application/json")&nbsp; &nbsp; w.Header().Set("Content-Encoding", "gzip")&nbsp; &nbsp; body, err := json.Marshal(box)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; // Your error handling&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; }&nbsp; &nbsp; writer, err := gzip.NewWriterLevel(w, gzip.BestCompression)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; // Your error handling&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; }&nbsp; &nbsp; defer writer.Close()&nbsp; &nbsp; writer.Write(body)}func main() {&nbsp; &nbsp; http.HandleFunc("/compressedget", writeJsonResponseCompressed)&nbsp; &nbsp; log.Fatal(http.ListenAndServe(":8081", nil))}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go