【问题标题】:Golang file upload: close connection if file is too largeGolang文件上传:如果文件太大则关闭连接
【发布时间】:2014-10-15 21:11:36
【问题描述】:

我想允许上传文件。 Go 被用于服务器端来处理请求。每当他们尝试上传的文件太大时,我想发送响应“文件太大”。我想这样做,之前整个文件被上传(带宽)。

我正在使用以下 sn-p,但它只是在客户端完成上传后才发送响应。它保存一个 5 kB 的文件。

const MaxFileSize = 5 * 1024
// This feels like a bad hack...
if r.ContentLength > MaxFileSize {
    if flusher, ok := w.(http.Flusher); ok {
        response := []byte("Request too large")
        w.Header().Set("Connection", "close")
        w.Header().Set("Content-Length", fmt.Sprintf("%d", len(response)))
        w.WriteHeader(http.StatusExpectationFailed)
        w.Write(response)
        flusher.Flush()
    }
    conn, _, _ :=  w.(http.Hijacker).Hijack()
    conn.Close()
    return
}

r.Body = http.MaxBytesReader(w, r.Body, MaxFileSize)

err := r.ParseMultipartForm(1024)
if err != nil {
    w.Write([]byte("File too large"));
    return
}

file, header, err := r.FormFile("file")
if err != nil {
    panic(err)
}

dst, err := os.Create("upload/" + header.Filename)
defer dst.Close()
if err != nil { 
    panic(err)
}

written, err := io.Copy(dst, io.LimitReader(file, MaxFileSize))
if err != nil {
    panic(err)
}

if written == MaxFileSize {
    w.Write([]byte("File too large"))
    return
}
w.Write([]byte("Success..."))

【问题讨论】:

  • 棘手。也许您可以使用 io.CopyN 读取 MaxFileSize + 1 字节。如果err != EOF,则超出限制或存在其他问题。不过,我不确定如果您这样做,用户会在浏览器中看到什么行为——试一试看看。另外,我知道这是测试代码,但是从panics 切换到错误返回对于您的生产代码来说是个好主意。
  • 感谢您的建议。用CopyN 替换Copy 并读取MaxFileSize + 1 字节没有帮助(在浏览器端)。至于恐慌,我通常有一个特殊的RecoverHandler,它可以从恐慌中恢复并产生一个很好的错误 400 页面。不过感谢您的关注。

标签: http upload go


【解决方案1】:

大多数客户端在写入请求之前不会读取响应。从服务器响应错误不会导致这些客户端停止写入。

net/http 服务器支持100 continue status。要使用此功能,服务器应用程序应在读取请求正文之前以错误响应:

func handler(w http.ResponseWriter, r *http.Request) {
  if r.ContentLength > MaxFileSize {
     http.Error(w, "request too large", http.StatusExpectationFailed)
     return
  }
  r.Body = http.MaxBytesReader(w, r.Body, MaxFileSize)
  err := r.ParseMultipartForm(1024)

  // ... continue as before

如果客户端发送了“Expect: 100-continue”标头,那么客户端应该在写入请求正文之前等待 100 continue 状态。当服务器应用程序读取请求正文时,net/http 服务器会自动发送 100 continue 状态。服务器可以通过在读取请求之前回复错误来阻止客户端写入请求正文。

net/http 客户端does not support the 100 continue status.

如果客户端没有发送期望头并且服务器应用程序从请求处理程序返回而没有读取完整的请求正文,则 net/http 服务器读取并丢弃最多 256

【讨论】:

  • 有没有办法“要求”客户端发送Expect: 100-continue 标头?我现在解决它的方式(有问题的编辑),感觉有点hacky。不过还是谢谢你的回答!
  • 你是怎么解决这个问题的?你能分享一个解决方案吗? AFAICT http.ServeHTTP(r,w) 自动响应 100-continue 并阻止服务器执行此操作。
  • 服务器自动响应 100 continue on first read of the request body。在响应 StatusExpectationFailed 之前不要阅读请求正文。
猜你喜欢
  • 2012-07-30
  • 2010-11-06
  • 2013-08-27
  • 1970-01-01
  • 2013-10-16
  • 2016-07-15
  • 1970-01-01
  • 1970-01-01
  • 2015-12-20
相关资源
最近更新 更多