Blob不能直接赋值给input[type="file"],必须用FormData+fetch或XMLHttpRequest手动上传;append时需传文件名参数以确保服务端正确接收,且不可手动设置Content-Type头。

表单提交时 Blob 对象不能直接作为 input[type="file"] 的值
浏览器禁止 JS 脚本直接给 input[type="file"] 赋值(包括 Blob),这是安全限制。你无法通过 fileInput.files = new DataTransfer().files 或类似方式“塞”进一个 Blob 来触发原生表单提交——FileList 是只读的,且 Blob 本身不是 File。
所以,如果目标是「用 Blob 上传」,必须绕过原生文件控件,改用 FormData + fetch 或 XMLHttpRequest 手动构造请求。
- Blob 可以直接 append 到
FormData,key 名会作为服务端接收的字段名 - 若需模拟原生表单的
name和文件名,append 时传第三个参数:例如formData.append('avatar', blob, 'photo.jpg') - 不传文件名时,服务端收到的文件名可能是空字符串或默认为
'blob',取决于后端框架处理逻辑
如何把 Blob 正确 append 到 FormData 并发送
关键点在于:Blob 本身没有 name 或 lastModified,但 FormData.append() 支持显式指定文件名,这会影响 Content-Disposition 头里的 filename= 字段。
示例:
立即学习“前端免费学习笔记(深入)”;
const blob = new Blob(['hello world'], { type: 'text/plain' });
const formData = new FormData();
formData.append('document', blob, 'readme.txt'); // ← 第三个参数决定服务端看到的文件名
<p>fetch('/upload', {
method: 'POST',
body: formData
// 注意:不要设 Content-Type!浏览器会自动设置 multipart/form-data 并带上 boundary
});
- 手动设置
headers: { 'Content-Type': 'multipart/form-data' }会导致失败——boundary 丢失,后端解析出错 - 如果 Blob 实际来自截图、录音或 canvas.toBlob(),确保它已加载完成(比如
canvas.toBlob(callback)的回调里再 append) - 大 Blob(如百 MB 视频)建议加上传进度监听,用
fetch的AbortController或XMLHttpRequest.upload.onprogress
需要兼容旧浏览器?优先选 XMLHttpRequest
fetch 对 FormData 的支持在 Safari 10.1+、Chrome 42+ 才稳定;IE 完全不支持 fetch。若需支持 IE11 或老安卓 WebView,必须用 XMLHttpRequest。
示例:
立即学习“前端免费学习笔记(深入)”;
const xhr = new XMLHttpRequest();
xhr.open('POST', '/upload');
xhr.upload.onprogress = e => console.log((e.loaded / e.total * 100).toFixed(1) + '%');
xhr.onload = () => console.log(xhr.status, xhr.responseText);
<p>const formData = new FormData();
formData.append('file', blob, 'data.bin');
xhr.send(formData);
-
xhr.send(formData)会自动设置正确的Content-Type头 - 不要调用
xhr.setRequestHeader()覆盖它 - IE11 不支持
Blob构造函数传入 typed array(如new Uint8Array(...)),需先转成ArrayBuffer再生成 Blob
后端收到的文件名和类型可能和预期不符
服务端是否拿到你期望的文件名和 MIME 类型,取决于前端 append 时传的第三个参数和 Blob 自身的 type 属性。两者不一致时,不同后端行为不同:
- Node.js
busboy/multer:优先用Content-Type头(即 Blob 的type),文件名取自Content-Disposition中的filename - PHP
$_FILES:文件名来自Content-Disposition,type字段来自Content-Type头,但部分 Nginx 配置会清空或覆盖它 - 如果你 append 时没传第三参数,Python Flask 的
request.files['xxx'].filename可能为空字符串
最稳妥的做法:append 时明确传文件名,并确保 Blob 的 type 与实际内容匹配(比如 PDF 就用 'application/pdf',别用 'text/plain')。否则后端校验或存储逻辑可能出问题。



















