直接调用c.FormFile("file")可获取*multipart.FileHeader,前提前端enctype="multipart/form-data"且input name与参数严格一致;不匹配返回echo.ErrNotFound,常见错误包括前端误用application/json、中间件提前读取body导致失败。

怎么用 c.FormFile() 接收单个文件
直接调用 c.FormFile("file") 就能拿到 *multipart.FileHeader,前提是前端表单用了 enctype="multipart/form-data" 且 <input type="file" name="file"> 的 name 和参数完全一致(区分大小写)。不匹配会返回 echo.ErrNotFound,不是 nil。
常见错误包括:
- 前端用
application/json发 base64 字符串,后端却调c.FormFile()→ 返回echo.ErrMissingFile - 在中间件里提前读了
c.Request.Body→ 后续c.FormFile()失败,因为 body 已被消耗 - 误以为
fh.Size是可读字节数,直接os.Create()写空文件 → 实际没数据,文件为空
真正读取内容必须调 fh.Open(),它返回 io.ReadCloser;记得 defer f.Close(),否则高并发下容易触发 too many open files。
怎么接收多个同名文件(multiple)
c.FormFile("files") 永远只返回第一个,这是 Go 标准库行为,不是 Echo 的限制。要拿全部,必须用 c.MultipartForm()。
实操要点:
- HTML 中写
<input type="file" name="files" multiple>,不用files[]这种 PHP 风格命名 - 调
form, err := c.MultipartForm(),检查err == http.ErrNotMultipart判断是否为 multipart 请求 - 取文件列表:
form.File["files"]是[]*multipart.FileHeader类型 - 每个文件都要单独
fileHeader.Open(),并在循环内defer f.Close()(不能放在循环外) - 用
io.Copy(dst, f)流式保存,别用ioutil.ReadAll()全部加载进内存
注意:空文件(fileHeader.Size == 0)或重复字段可能混在列表里,需手动过滤。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
上传前怎么拦截超大文件?
FileHeader.Size 只有解析完才可用,无法前置校验。可靠拦截得靠两层:
- 在 handler 开头读
c.Request().Header.Get("Content-Length"),转成int64后比对阈值(如10 * 1024 * 1024),超限直接返回http.StatusRequestEntityTooLarge(413) - 同时设置
e.MaxMultipartMemory = 8 * 1024 * 1024(例如 8MB),让超过该内存上限的 multipart 解析失败并报错 —— 这个值必须小于你的业务阈值,否则超限部分仍会落盘
注意:Content-Length 在分块传输(chunked encoding)时不存在,但 Echo 默认不支持自动处理 chunked 表单上传,实际中绝大多数客户端仍会发这个 header。
文件名和路径怎么防攻击?
fileHeader.Filename 完全不可信,含路径遍历(../../etc/passwd)、空字节、控制字符等风险。Echo 不做任何净化,必须自己处理。
安全做法:
- 用
filepath.Base()提取原始文件名,再用正则或白名单过滤非法字符 - 扩展名必须按
fileHeader.Header.Get("Content-Type")或魔数(magic bytes)校验,不能只看后缀 - 存储路径用
path.Join("uploads", safeName),但确保"uploads"是绝对路径或已创建好目录 - 生成唯一文件名推荐
uuid.NewString()或time.Now().UnixNano(),别拼接原始名
最容易被忽略的是:没检查目标目录是否存在,os.Create() 会因父目录缺失而失败;也没设好 umask 或权限,导致文件不可读或被越权访问。


















