英文:
gzip compression to http responseWriter
问题
我是你的中文翻译助手,以下是翻译好的内容:
我刚开始学习Go语言,但正在使用REST API进行实践。我在两个函数中使用json.Marshal和json.Encoder时无法获得相同的行为。
我想使用以下函数来对响应进行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
以下是Go函数的代码:
func CompressedGet(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
box := Box{Width: 10, Height: 20, Color: "green", 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)
它可以正常工作。
英文:
I'm new to Go. But am playing with a REST Api. I cant get the same behavior out of json.Marshal as json.Encoder in two functions i have
I wanted to use this function to gzip my responses:
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()
}
But this function returns this:
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
Here is the go function:
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()
}
But when i uncomment:
//gz := gzip.NewWriter(w)
//defer gz.Close()
//json.NewEncoder(gz).Encode(box)
it works fine.
答案1
得分: 2
我会避免手动对[]byte
进行gzip压缩。你可以轻松地使用标准库中已经存在的写入器。此外,你可以看一下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 {
// 处理错误
return
}
writer, err := gzip.NewWriterLevel(w, gzip.BestCompression)
if err != nil {
// 处理错误
return
}
defer writer.Close()
writer.Write(body)
}
func main() {
http.HandleFunc("/compressedget", writeJsonResponseCompressed)
log.Fatal(http.ListenAndServe(":8081", nil))
}
希望对你有帮助!
英文:
I would avoid gzip-ing []byte
manually. You can easily use already existing writers from standard library. Additionally, take a look on compress/flate
which I think should be use instead of 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))
}
答案2
得分: 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
英文:
I think the problem is the use of fmt.Fprint(w, gzipFast(&b))
.
If you look to the definition of gzipFast it returns a []byte
. You are putting this slice into the print function, which is "printing" everything into w
.
If you look at the definition of the io.Writer:
type Writer interface {
Write(p []byte) (n int, err error) }
You see that the writer can handle []byte
as input.
Instead of fmt.Fprint(w, gzipFast(&b))
you should use w.Write(gzipFast(&b))
. Then you don't need to uncomment:
//gz := gzip.NewWriter(w)
//defer gz.Close()
//json.NewEncoder(gz).Encode(box)
Everything as a small example, which shows what is happening in your code:
答案3
得分: 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写入器中缓冲但尚未写入最终流的内容将不会被收集起来。
英文:
You need to flush or close your gzip writer before accessing the underlying bytes, e.g.
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()
}
Otherwise what's been buffer in the gzip writer, but not yet written out to the final stream isn't getting collected up.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论