Golang文件上传:如果文件太大,关闭连接。

huangapple go评论84阅读模式
英文:

Golang file upload: close connection if file is too large

问题

我想要允许上传文件。服务器端使用Go来处理请求。当用户尝试上传的文件过大时,我想要发送一个"文件太大"的响应。我希望在整个文件上传完成之前就发送这个响应,以节省带宽。

我正在使用以下代码片段,但它只会在客户端完成上传后才发送响应。它保存了一个5KB的文件。

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..."))

请注意,这只是一个示例代码片段,你可能需要根据你的实际需求进行适当的修改。

英文:

I want to allow uploading files. Go is being used server-side to handle requests. I would like to send a response "File too large" whenever the file they're trying to upload is too large. I would like to do so, <i>before</i> the entire file is uploaded (bandwidth).

I am using the following snippet, but it's only sending a response after the client is done uploading. It saves a 5 kB file.

const MaxFileSize = 5 * 1024
// This feels like a bad hack...
if r.ContentLength &gt; MaxFileSize {
	if flusher, ok := w.(http.Flusher); ok {
		response := []byte(&quot;Request too large&quot;)
		w.Header().Set(&quot;Connection&quot;, &quot;close&quot;)
		w.Header().Set(&quot;Content-Length&quot;, fmt.Sprintf(&quot;%d&quot;, 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(&quot;File too large&quot;));
	return
}

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

dst, err := os.Create(&quot;upload/&quot; + 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(&quot;File too large&quot;))
    return
}
w.Write([]byte(&quot;Success...&quot;))

答案1

得分: 20

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

net/http服务器支持100 continue状态。要使用此功能,服务器应在读取请求体之前返回错误:

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

  // ... 继续处理
}

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

net/http客户端不支持100 continue状态

如果客户端没有发送expect头部,并且服务器应用程序在请求处理程序中返回而没有完全读取请求体,则net/http服务器会读取并丢弃最多256 << 10字节的请求体。如果没有读取完整的请求体,服务器将关闭连接。

英文:

Most clients do not read the response until done writing the request. Responding with an error from the server will not cause these clients to stop writing.

The net/http server supports the 100 continue status. To use this feature, the server application should respond with an error before reading the request body:

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

  // ... continue as before

If the client sent the "Expect: 100-continue" header, then the client should wait for the 100 continue status before writing the request body. The net/http server automatically sends the 100 continue status when the server application reads the request body. The server can stop the client from writing the request body by replying with an error before reading the request.

The net/http client does not support the 100 continue status.

If the client did not send the expect header and the server application returns from the request handler without reading the complete request body, then the net/http server reads and discards up to 256 << 10 bytes of the request body. The server will closes the connection if the entire request body was not read.

huangapple
  • 本文由 发表于 2014年10月16日 05:11:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/26392196.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定