前端进阶之旅前端进阶之旅
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库Blob type MIME 嗅探 浏览器
浏览浏览器文件与多媒体

Blob.type 为空时能不能根据内容嗅探类型,浏览器给出什么保证?

Blob.type为空不代表内容无类型,浏览器不会自动读字节嗅探。要获取真实类型,需自行读取文件片段比对二进制签名,同时接受不确定性。

前端进阶之旅 · 一题精讲更新于 2026.09.05
浏览器#文件与多媒体
先看核心答案
理解线索

type的不可靠来源

  1. 生成机制参数type或文件扩展名映射
  2. 空值意义未映射到常见MIME,非损坏
  3. 嗅探成本需要异步读取文件片段

内容嗅探必须自行实现,浏览器不保证结果。

核心回答

先记住这个答案

浏览器按照文件扩展名或创建参数给出Blob.type,不解析内容。type为空字符串表示未识别,仍是合法Blob。判断实际类型应读取文件头部字节,比对已知魔数(如FF D8 FF是JPEG),并考虑无固定签名的格式。这个结果用于辅助校验,不能替代服务端策略。

  • type源于名字或声明,不是内容指纹
  • 空值读取头字节,用签名可比对
  • 签名嗅探有误报,需白名单兜底

type属性如何形成与空值来源

浏览器创建Blob或File时,type值来自构造函数参数,或文件选择控件按扩展名查询系统映射表,不会读取内容字节。PNG改名.txt后type变text/plain,换成冷门后缀则返回空字符串。空字符串不是错误,仅表示当前环境无法凭扩展名归类这个文件。

既然不读文件体,浏览器就不会为Blob做内容嗅探。不存在一个标准方法来猜测未知类型。开发者只能在拿到Blob后自行读取头部数据:用FileReader.readAsArrayBuffer或blob.arrayBuffer()。两种异步方式都能取到前几KB,然后将字节与已知魔数比较。

常见二进制格式都有签名,如GIF以GIF87a/GIF89a开头,PNG固定89 50 4E 47。文本类文件没有唯一前缀,只能按内容试探。因此,字节比对只适合有明确魔数的格式,对未知扩展名仍不可靠。

头像上传时用字节签名校验

设头像上传接口只收JPG和PNG。在Linux终端下,浏览器常给文件空type,用户手工改名也可能伪造。前端先用file.slice(0, 16)截取片段,转成ArrayBuffer,检查是否以FF D8 FF或89 50 4E 47开头。若都不匹配,就用“文件内容不是有效图片”提示并中断提交。

这个方法能拦截“文本文件强制改成.jpg”的情况,但对合法但无签名的SVG会误拒。要避免误伤,需要产品先定白名单:只允许有魔数签名且你检测过的格式,其余一律拒绝。若必须支持SVG,需要单独判断XML标签,而不能用通用嗅探。

读取头部的操作是异步的,要防止用户重复点击提交。建议在表单校验态里把文件对象缓存,依次await校验后再发请求。因为只读几十字节,大文件也不会撑爆内存,但代码需要处理ArrayBuffer的边界与字节对齐。

内容嗅探的失效条件与缓解

内容嗅探失效的典型场景是无固定签名的文本类型:text/plain、application/json、text/html都可能以空字节开头或带BOM。若想识别它们,需要解析内容结构,这会引入极大的不确定性与计算成本,不适合做通用方案。

另一个边界是同一签名对应多种子格式:ZIP文件被Office套件及安卓APK共同使用,仅凭首字节无法区分它们。WebP内部还有VP8/VP8L分支。当签名不够特异时,嗅探结论只能精确到容器级,而不是最终子类型。

面对这些失效,工程上应由后端在接收后做权威解码,前端只把Blob.type和字节签名作为预筛选。空type时不要提示“文件损坏”,应说“无法自动识别格式,请确认文件来源”。这既诚实,也避免误导用户去重传同一文件。

回答前,多想一步

容易答错的地方

type为空表示文件有问题
空字符串只是没有识别出MIME,不代表数据损坏或不可用。浏览器可能因扩展名未注册、用户重命名而给空值。很多合法Blob(如File对象)在构造时可任意指定type,空值也完全允许。
内容嗅探能替代type做安全校验
浏览器不保证嗅探正确,且没有标准实现。自写比对只能覆盖已知魔数,容易漏判或误判。攻击者可构造同时满足两种签名的文件,所以嗅探只能作为体验优化,不能作为安全边界。后端必须独立验证。
试着用自己的话回答

面试官还会怎么问?

具体如何读取Blob的前几个字节?

可以用blob.slice(0, 4).arrayBuffer()取到前4字节,然后转成Uint8Array和魔数常量比较。兼容旧浏览器用FileReader.readAsArrayBuffer,但arrayBuffer()在现代环境更简洁。注意需要处理异步错误。

多数图片类型都有签名吗?

常见有,JPEG、PNG、GIF、WebP、BMP都有固定前缀。但像SVG是XML文本,没有固定前几字节,不能仅靠签名判断。音频中WAV有RIFF头,MP3虽有ID3但可偏移,需要容错扫描。

Blob.type和File.type可否都当作扩展名推断?

可以,File继承自Blob,两者type生成规则一样,都基于文件名扩展名。因此改扩展名会让两者给出一样的错误结果,不能因为来自File就信任。真正的可靠性来自后续字节读取和服务器解析。

从一道题,走向一组知识

把知识连起来

文件与多媒体

File 与 Blob 在浏览器中有什么本质区别,什么时候不能只按 Blob 处理?

辨析File与Blob身份,有助于理解type属性在文件对象中的相同来源与局限。

文件与多媒体

<input type=file> 的 accept 属性能否当作安全校验,失败体验应怎样兜底?

accept属性也靠type过滤,但它不可靠,和此题内容嗅探边界相呼应。

参考资料

  • Blob: type property

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. type属性如何形成与空值来源
  3. 头像上传时用字节签名校验
  4. 内容嗅探的失效条件与缓解
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑