如何用Go限制下载速度?

时间:2015-04-04 10:12:26

标签: performance download go throttling rate

我目前正在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

2 个答案:

答案 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()