用http.handlefunc处理文件上传最简路径是调用request.parsemultipartform,且必须在读取request.body前调用,否则报eof错误;默认maxmemory为32mb,大文件需显式设置合理值以防内存溢出。

用 http.HandleFunc 处理文件上传最简路径
Go 标准库的 http 包本身不提供“一键上传”,但 request.ParseMultipartForm 是实际可用的起点。关键不是写多复杂,而是避免踩 maxMemory 和 ParseMultipartForm 调用时机这两个坑。
-
ParseMultipartForm必须在读取request.Body前调用,否则会返回http: multipart: Part.Read: EOF - 默认
maxMemory是 32MB,上传大文件时若不显式设置,整个文件会被加载进内存——应设为合理值(如32 ),超出部分自动流式写入临时磁盘 - 表单字段名(
name="file")必须与后端request.FormFile("file")中的字符串严格一致,大小写敏感
保存上传文件时绕过 os.Create 直接用 multipart.File
request.FormFile 返回的是 multipart.File 接口,本质是 *os.File 或临时文件句柄,直接 io.Copy 最安全,不用自己开文件再读写。
- 不要用
os.Create+io.Copy,容易因权限或路径问题失败;应直接dst, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) - 务必检查
err后立即defer dst.Close(),否则并发上传时可能耗尽文件描述符 - 文件名需过滤:从
header.Filename提取后做白名单校验(如只允许.jpg、.pdf),防止../../etc/passwd类路径遍历
下载文件用 http.ServeContent 而非 io.Copy
直接 io.Copy(w, f) 虽能传文件,但无法支持断点续传、范围请求(Range)、缓存协商(ETag/Last-Modified)。生产环境必须用 http.ServeContent。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 调用前需设置
w.Header().Set("Content-Disposition", "attachment; filename=\""+filename+"\""),否则浏览器可能内嵌显示而非下载 -
http.ServeContent第三个参数是modtime,建议用fi.ModTime(),否则 ETag 总是空,无法利用浏览器缓存 - 如果文件路径来自用户输入,先用
filepath.Clean并检查是否在允许目录下(如strings.HasPrefix(cleanPath, allowDir)),防目录穿越
模块化时把上传/下载逻辑抽成独立 handler 函数
别把所有逻辑塞进一个 http.HandleFunc。上传和下载各自封装为接收 http.ResponseWriter 和 *http.Request 的函数,方便单元测试和复用。
- 上传 handler 应返回结构体(如
{Success: true, URL: "/download/xxx"}),而不是直接写 JSON —— 留出中间件注入日志、鉴权、限流的空间 - 下载 handler 不要硬编码文件系统路径,通过闭包或依赖注入传入
baseDir string,便于测试时用memfs替换 - 注意
http.Error会终止 handler,但不会关闭连接;错误响应也应设Content-Type: application/json并写明"error": "xxx",方便前端统一处理
真正麻烦的从来不是怎么写完,而是上传时没设 maxMemory 导致 OOM,或者下载时忘了 Content-Disposition 让文件在浏览器里直接打开了——这些细节不验证一遍,上线就出事。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










