2016-08-24 118 views
0

我是新來的Go。但我正在玩REST Api。我不能得到相同的行爲進行json.Marshal作爲json.Encoder的兩個功能我有gzip壓縮到http responseWriter

我想利用這個功能給gzip我的迴應:

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 

這裏是去功能:

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) 

它工作正常。

+0

也許因爲3條線是不必要的? gzipFast函數已經在對json編碼框進行gzip壓縮。 – Sridhar

回答

1

您需要在訪問基礎字節之前刷新或關閉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寫入器中的緩衝區,但尚未寫出到最後的流沒有被收集起來。

+0

這解決了它。謝謝! – stihl

1

我覺得問題是使用fmt.Fprint(w, gzipFast(&b))

如果你看看gzipFast的定義,它會返回一個[]byte。您正在將此切片放入打印功能中,該功能將所有內容「打印」爲w

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

type Writer interface { 
     Write(p []byte) (n int, err error) } 

你看,作者可以處理[]byte作爲輸入。您可以使用w.Write(gzipFast(&b))而不是fmt.Fprint(w, gzipFast(&b))。那麼你就需要取消註釋:

//gz := gzip.NewWriter(w) 
//defer gz.Close() 
//json.NewEncoder(gz).Encode(box) 

一切作爲一個小例子,這說明什麼是你的代碼發生的事情:

https://play.golang.org/p/6rzqLWTGiI

0

我會避免用gzip荷蘭國際集團手動[]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)) 
} 
+0

我同意,這對我來說是學習一些東西的考驗。如果這個API是生產應用程序,那麼你的解決方案是最好的。 – stihl