c.formfile("file") 只获取一个文件,因其专为单文件设计,仅返回同名字段首个 *multipart.fileheader;多文件需调用 c.request().parsemultipartform(32

为什么 c.FormFile("file") 只拿到一个文件?
因为 c.FormFile 是专为单文件设计的快捷方法,它只取同名字段的第一个 *multipart.FileHeader。前端拖拽多个文件或使用 <input multiple> 时,浏览器会把所有文件打包进同一个表单字段(如 file),但 Echo 不会自动展开成切片。
✅ 正确做法是绕过 c.FormFile,直接访问解析后的原始结构:
c.Request().ParseMultipartForm(32 先强制解析(单位字节,这里设 32MB)- 检查
c.Request().MultipartForm.File["file"]是否为非空切片 - 遍历该切片,每个元素都是独立的
*multipart.FileHeader,含Filename、Size、Header
如何避免大文件上传被静默截断?
Echo 默认启用 BodyLimit 中间件,值为 4MB。50MB 视频或 ZIP 直接返回 413 Request Entity Too Large,且请求根本不会进入路由逻辑——你连日志都看不到。
✅ 必须显式配置并放在路由注册前:
- 启动时加中间件:
e.Use(middleware.BodyLimit("100MB")) - 确保该中间件在
e.POST("/upload", ...)之前注册 - 若用自定义 HTTP server,也要同步设置
http.Server.ReadTimeout和MaxHeaderBytes
怎么安全保存多个文件而不爆内存?
别用 io.ReadAll(src) 把整个文件读进内存;也别直接 c.SaveToFile(header, dstPath)(它内部会全量加载)。尤其并发上传时,容易触发 OOM。
Echo框架 5.1.0 版本源码包下载,适合关注 RealIP 行为变化、StartConfig.Listener、NewDefaultFS 和观测性中间件入口的开发团队。
✅ 推荐组合方式:
- 对每个
FileHeader,调用header.Open()得到multipart.Part流 - 用
os.Create(dst)创建目标文件句柄 - 用
io.Copy(dst, src)流式写入(底层是 32KB buffer,默认足够) - 务必
defer src.Close()和defer dst.Close()
示例关键行:src, _ := header.Open(); dst, _ := os.Create("upload/" + header.Filename); io.Copy(dst, src)
CORS 和预检失败导致拖拽无响应?
拖拽松手后没反应,不是前端 JS 写错了,而是浏览器在发 OPTIONS 预检时被拦了——常见于本地开发(localhost:3000 → localhost:1323)。
✅ 检查三处:
- 前端 fetch 是否带
credentials: "omit"(或按需设"include") - Echo 是否启用 CORS 中间件:
e.Use(middleware.CORSWithConfig(...)),且AllowOrigins包含前端地址 -
AllowHeaders必须显式包含"Content-Type",否则预检失败
真正容易被忽略的是:预检失败时 Network 面板里看不到 POST 请求,只会卡在 OPTIONS 上,控制台报 net::ERR_CONNECTION_RESET 或 Failed to fetch ——此时要先盯死 OPTIONS 响应头。










