new file([blob], filename, {type: mimetype}) 是唯一可靠方式,可生成带 name 和 type 的真实 file 实例,兼容现代浏览器,ios safari 16.4+ 才支持,旧版需降级用 formdata.append('file', blob, filename)。

如何用 Blob 构造出带名字和 MIME 的 File 对象
直接说结论:new File([blob], filename, {type: mimeType}) 是唯一可靠方式。不是用 blob.name 赋值,也不是靠 URL 或 slice() 伪装——那些都不生成真正的 File 实例。
浏览器里 File 是 Blob 的子类,但多了 name 和 lastModified 两个关键属性。表单上传、input[type="file"] 模拟、拖拽 API 入参等场景,后端或框架常依赖 File.name 做文件路由或校验,光有 Blob 会失败。
-
filename必须是字符串,不能含路径(如"./uploads/photo.jpg"会被忽略,只取"photo.jpg") -
type参数不强制,但建议显式传入;若为空字符串或无效 MIME,file.type会 fallback 为"",部分上传库(如 axios + FormData)可能丢弃该字段 - 传入的
blob可以是原始Blob,也可以是ArrayBuffer或Uint8Array,File构造函数内部会自动转成Blob
File 构造失败的常见报错和原因
典型错误是 TypeError: Failed to construct 'File': parameter 1 is not of type 'Blob'。这不是因为你没传 Blob,而是传了“看起来像 Blob”但实际不是的对象。
- 从
fetch().then(r => r.blob())得到的是真Blob,可用 - 用
new Blob([arrayBuffer])创建的是真Blob,可用 - 但
response.arrayBuffer()返回的是Promise<arraybuffer></arraybuffer>,直接塞进new File([res.arrayBuffer()], ...)就会报错——你传的是 Promise,不是 ArrayBuffer - 用
URL.createObjectURL(blob)生成的字符串是地址,不是Blob,也不能当构造参数
正确写法示例:
立即学习“前端免费学习笔记(深入)”;
fetch('/api/image')
.then(r => r.arrayBuffer())
.then(buf => {
const blob = new Blob([buf], {type: 'image/png'});
const file = new File([blob], 'avatar.png', {type: 'image/png'});
// ✅ file instanceof File === true
// ✅ file.name === 'avatar.png'
// ✅ file.type === 'image/png'
});
兼容性与移动端要注意的细节
File 构造函数在 Chrome 76+、Firefox 69+、Safari 16.4+ 支持,iOS Safari 16.4 是关键分水岭——低于此版本(比如 iOS 15.x)会直接抛 ReferenceError: File is not defined。
- 不要试图 polyfill
File构造函数:它的原型链和内部 slot(如[[FileSystem]])无法模拟 - 降级方案只能是绕过
File,改用FormData.append('file', blob, filename)直接传Blob,前提是后端接受无名二进制体(此时Content-Disposition的filename由append第三个参数注入) - Android WebView 旧版本(Chrome typeof File !== 'undefined' && 'name' in File.prototype
为什么不用 blob.name = 'xxx'?
因为 Blob.name 是只读属性,赋值无效,且不会影响任何行为。这是最常被误信的“快捷方式”。
const b = new Blob(['test']); b.name = 'hello.txt'; console.log(b.name); // undefined- 即使你用 Object.defineProperty 强行定义,也改不了它在
FormData中的表现:浏览器仍按匿名Blob处理,Content-Disposition不带filename - 某些调试器(如 Chrome DevTools)显示
name字段是假象——它只是把toString()结果格式化成类似Blob {size: 4, type: "", name: "unknown"},不代表真实可读属性
真要加名字,只有 new File 这一条路。别省那几行代码,否则后续所有基于 file.name 的逻辑都会静默失效。











