为了账号安全,请及时绑定邮箱和手机立即绑定

gzip 压缩到 http responseWriter

gzip 压缩到 http responseWriter

Go
牧羊人nacy 2022-03-03 15:07:22
我是 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)它工作正常。
查看完整描述

3 回答

?
心有法竹

TA贡献1866条经验 获得超5个赞

您需要在访问底层字节之前刷新或关闭您的 gzip 编写器,例如


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

    var b bytes.Buffer

    gz := gzip.NewWriter(&b)

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

        gz.Close()

        panic(err)

    }

    gz.Close()

    return b.Bytes()

}

否则,gzip writer 中的缓冲区,但尚未写入最终流的内容不会被收集起来。


查看完整回答
反对 回复 2022-03-03
?
凤凰求蛊

TA贡献1825条经验 获得超4个赞

我认为问题在于使用fmt.Fprint(w, gzipFast(&b)).


如果您查看 gzipFast 的定义,它会返回一个[]byte. 您正在将此切片放入 print 函数中,该函数将所有内容“打印”到w.


如果你看一下 io.Writer 的定义:


type Writer interface {

        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


查看完整回答
反对 回复 2022-03-03
?
holdtom

TA贡献1805条经验 获得超10个赞

我会避免[]byte手动压缩。您可以轻松地使用标准库中现有的编写器。另外,看看compress/flate我认为应该使用哪个而不是 gzip。


package main


import (

    "net/http"

    "encoding/json"

    "compress/gzip"

    "log"

)


type Box struct {

    Width int `json:"width"`

}


func writeJsonResponseCompressed(w http.ResponseWriter, r *http.Request) {


    box := &Box{Width: 10}


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

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


    body, err := json.Marshal(box)

    if err != nil {

        // Your error handling

        return

    }


    writer, err := gzip.NewWriterLevel(w, gzip.BestCompression)

    if err != nil {

        // Your error handling

        return

    }


    defer writer.Close()


    writer.Write(body)

}


func main() {

    http.HandleFunc("/compressedget", writeJsonResponseCompressed)

    log.Fatal(http.ListenAndServe(":8081", nil))

}


查看完整回答
反对 回复 2022-03-03
  • 3 回答
  • 0 关注
  • 162 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信