我目前正在Go中开发下载服务器。我需要将用户的下载速度限制在100KB / s。
这是我的代码:
func serveFile(w http.ResponseWriter, r *http.Request) {
fileID := r.URL.Query().Get("fileID")
if len(fileID) != 0 {
w.Header().Set("Content-Disposition", "attachment; filename=filename.txt")
w.Header().Set("Content-Type", r.Header.Get("Content-Type"))
w.Header().Set("Content-Length", r.Header.Get("Content-Length"))
file, err := os.Open(fmt.Sprintf("../../bin/files/test.txt"))
defer file.Close()
if err != nil {
http.NotFound(w, r)
return
}
io.Copy(w, file)
} else {
io.WriteString(w, "Invalid request.")
}
}
然后我在github上找到了一个包,我的代码变成了以下内容:
func serveFile(w http.ResponseWriter, r *http.Request) {
fileID := r.URL.Query().Get("fileID")
if len(fileID) != 0 {
w.Header().Set("Content-Disposition", "attachment; filename=Wiki.png")
w.Header().Set("Content-Type", r.Header.Get("Content-Type"))
w.Header().Set("Content-Length", r.Header.Get("Content-Length"))
file, err := os.Open(fmt.Sprintf("../../bin/files/test.txt"))
defer file.Close()
if err != nil {
http.NotFound(w, r)
return
}
bucket := ratelimit.NewBucketWithRate(100*1024, 100*1024)
reader := bufio.NewReader(file)
io.Copy(w, ratelimit.Reader(reader, bucket))
} else {
io.WriteString(w, "Invalid request.")
}
}
但是我收到了这个错误:
损坏的内容错误
您尝试查看的页面因为错误而无法显示 检测到数据传输。
这是我在Go游乐场的代码:http://play.golang.org/p/ulgXQl4eQO
答案 0 :(得分:2)
使用http.ServeContent
可能会更好地使用{{3}}而不是自己获取正确的内容类型和长度标题,而不是为您做到这一点(以及支持"如果-Modified-Since",范围请求等。如果您可以提供" ETag"标题,它还可以处理" If-Range"和" If-None-匹配"请求。)
如前所述,它通常更倾向于限制写入方面但是包装http.ResponseWriter
很不方便,因为各种http函数也检查可选接口,例如{{1} }和http.Flusher
。包裹http.Hijacker
需要的io.ReadSeeker
要容易得多。
例如,这样的事情可能是:
ServeContent
答案 1 :(得分:1)
我没有看到错误,但我注意到代码存在一些问题。为此:
w.Header().Set("Content-Type", r.Header.Get("Content-Type"))
您应该使用mime package'
func TypeByExtension(ext string) string
确定内容类型。 (如果最终将空字符串默认为application/octet-stream
)
有关:
w.Header().Set("Content-Length", r.Header.Get("Content-Length"))
您需要从文件本身获取内容长度。通过使用请求内容长度,对于GET
,这基本上最终为无操作,但对于POST
,您发回的错误长度,这可能会解释您的错误&# 39;重看。打开文件后,请执行以下操作:
fi, err := file.Stat()
if err != nil {
http.Error(w, err.Error(), 500)
return
}
w.Header().Set("Content-Length", fmt.Sprint(fi.Size()))
最后一件事,当您打开文件时,如果出现错误,您不需要关闭文件句柄。这样做是这样的:
file, err := os.Open(...)
if err != nil {
http.NotFound(w, r)
return
}
defer file.Close()