最稳妥的浏览器原生文件上传方式是使用 FormData,它自动处理 boundary 和 multipart/form-data 头;切忌手动设置 Content-Type 或 JSON.stringify 文件,大文件需用 XMLHttpRequest 监听进度或分片上传,并确保前后端字段名、中间件配置及 Nginx 限制等细节一致。

用 FormData 构造上传数据最稳妥
浏览器原生上传不依赖第三方库,核心就是 FormData。它能自动处理文件字段的边界(boundary)、编码和 multipart/form-data 头,比手动拼接字符串或设置 Content-Type 可靠得多。
常见错误是直接把 File 对象 JSON.stringify 后发请求——这会失败,因为二进制内容无法被 JSON 序列化。
- 从
获取files[0]后,直接append到FormData实例里 - 字段名必须和后端约定一致,比如后端期待
file字段,就写formData.append('file', file) - 如需额外参数(如用户 ID、分类),也用
append加入,不用单独塞进body或 query
fetch 上传时别设 Content-Type
用 fetch 发送 FormData 时,**绝对不要手动设置 headers: {'Content-Type': 'multipart/form-data'}**。浏览器会自动添加带随机 boundary 的正确头;手动设了反而会导致 boundary 缺失,后端解析失败,典型报错是 Unexpected end of multipart data 或空文件。
正确写法只传 body:
立即学习“Java免费学习笔记(深入)”;
fetch('/upload', {
method: 'POST',
body: formData // 不要加 headers
})
大文件上传要考虑 onprogress 和分片
单次传几百 MB 文件容易超时、卡死或被代理截断。纯前端可控的底线方案是监听 XMLHttpRequest.upload.onprogress(fetch 目前无标准进度事件):
- 必须用
XMLHttpRequest而非fetch才能拿到实时上传进度 - 分片上传需后端配合:前端切块、按序号上传、后端合并。前端切片用
file.slice(start, end),注意 Blob 方法在 Safari 中对 large file 支持不稳定 - 上传中断续传需服务端记录已接收块,前端校验 MD5 或 SHA-1(计算大文件哈希会阻塞主线程,要用
Web Worker)
后端接收不到文件?先查 req.headers['content-type']
前端看似发成功,但 Node.js(Express/Koa)、Python(Flask/Django)等后端收不到 req.file 或 request.files,大概率是 content-type 不匹配或中间件未启用。
- Express 需显式加
multer或busboy解析 multipart;仅app.use(express.json())不管用 - 检查 Node.js 日志里
req.headers['content-type']是否以multipart/form-data; boundary=...开头,如果不是,说明前端误设了 header 或用了错误 body 格式 - Nginx 默认限制上传大小为 1MB,超限会返回 413,需调
client_max_body_size











