ios safari 不支持 audio/*,必须显式列出 mime 类型和扩展名;accept 仅影响文件选择界面,无法阻止非法文件上传;真实类型校验必须依赖文件头 magic bytes,前端限制可被绕过。

accept="audio/*" 为什么在 iOS Safari 里选不出音频文件
不是你写错了,是 Safari(尤其 iOS)根本不用 audio/* 做筛选。它只认具体 MIME 类型或扩展名,audio/* 在很多版本中直接被忽略,导致相册、iCloud 音频入口不出现,甚至整个选择框卡死。
- 必须显式列出常见音频 MIME 类型:
audio/mpeg,audio/mp4,audio/wav,audio/ogg,audio/flac - 同时补上对应扩展名:
.mp3,.m4a,.wav,.ogg,.flac(注意带点号) - 逗号后绝对不能有空格:
audio/mpeg,.mp3✅,audio/mpeg , .mp3❌(旧版 Safari 直接丢弃整个accept属性) - 华为 EMUI、小米 MIUI 的 WebView 可能连
audio/mpeg都不识别,只响应.mp3—— 所以双写是底线
写了 accept 但用户还是拖进了 .exe 或 .html 怎么办
accept 从不阻止上传,它只影响点击“选择文件”时的对话框默认视图。用户点“所有文件”、拖拽、粘贴、用 DevTools 删除 accept 属性,都能绕过。
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- 前端 JS 必须在
change事件里遍历event.target.files每一项 - 别信
file.type:把hack.exe改名成voice.mp3,file.type就可能返回audio/mpeg - 优先用
file.name.toLowerCase().endsWith('.mp3')或正则/\.mp3$|\.wav$/i - 对关键业务,用
FileReader读前 4 字节比对 magic number:FF FB(MP3)、RIFF(WAV)、OggS(OGG)
后端校验音频文件的真实类型,不能只看请求头
前端所有限制都可被 curl、Postman 或修改表单绕过。req.headers['content-type'] 和 req.file.mimetype(Node.js)完全不可信。
- 必须读取上传文件二进制流前若干字节,用真实文件头判断类型
- PDF 是
%PDF,MP3 是FF FB,WAV 是RIFF—— 这些才是唯一可信依据 - 推荐库:
file-type(Node.js)、python-magic(Python)、Apache Tika(Java) - 验证通过后,务必重命名文件(如
audio_123456789.mp3),剥离原始扩展名,再根据检测结果附加安全后缀
移动端音频上传的隐藏坑:iOS 录音 vs iCloud vs 相册
iOS Safari 对 accept 的处理极不统一:设 accept="audio/*" 后,录音功能可用,但 iCloud 音频和相册音频可能直接消失;设 accept="audio/mpeg,.mp3",又可能只显示 MP3,漏掉 M4A。
- 最稳方案:
accept="audio/mpeg,audio/mp4,audio/x-m4a,.mp3,.m4a,.wav" - 安卓部分定制系统(如 EMUI)会忽略所有
audio/xxx,只响应扩展名,所以.mp3必须带上 - 如果用第三方 UI 组件(如 Ant Design 的
Upload),确认它是否透传accept到底层原生<input type="file">—— 查看 DOM 就知道 - 真要兼容全链路,得在服务端支持多种音频封装格式,并统一转码或存为标准格式(如 MP3)
accept,而是后端读取文件头那几字节的逻辑。前端写的再细,只要服务端没校验 magic bytes,就等于没设防。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










