1. 版权

本文为原创, 遵循 CC 4.0 BY-SA 版权协议, 转载需注明出处: https://blog.csdn.net/big_cheng/article/details/120095982.
文中代码属于 public domain (无版权).

2. 内容

以Golang webapp为例.

html

https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/Input/file
https://developer.mozilla.org/zh-CN/docs/Web/API/File

if (document.getElementById('file1').files[0].size > 1024*1024) {
    // 文件超过1M
}

https://developer.mozilla.org/zh-CN/docs/Web/API/FormData/append
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#uploading_a_file
使用FormData 上传文件到服务器.

nginx

server {
    ...
    client_max_body_size 210K;
    
    location = /upload {
        ...
        client_max_body_size 1034K;
    }
    
    ...
}

1034K = 文件1M + 请求体part的分隔符(10K, 按1%). 如果还有其他part(普通Form字段), 也需加上.

net/http Handler

func (w http.ResponseWriter, r *http.Request)

a. (解析前)限制请求体大小


if r.ContentLength >= 0 && r.ContentLength > 1034*1024 {
    // return errors.New("http: request body too large")
}
r.Body = http.MaxBytesReader(w, r.Body, 1034*1024)

如果请求体大小已知并且超长, 可以直接返错, 以避免上传1M+10K字节之后才报错而浪费流量.

b. 解析时限制上传文件占用的内存


r.ParseMultipartForm(50 * 1024) // e.g. 50K

超出时Go 会自动转存为磁盘临时文件.

c. 请求结束时清理临时文件

myhandler(w http.ResponseWriter, r *http.Request) {
    defer func() {
        if r.MultipartForm != nil {
            r.MultipartForm.RemoveAll()
        }
    }()
    
    ...
}
3. 附录

读取上传文件

fh := r.MultipartForm.File["file1"] // multipart.FileHeader
f, _ := fh.Open() // multipart.File (注: 示例代码, 忽略了err)
defer f.Close()
f.Read(make([]byte, 1024))
...