安卓 webview 和 miui/emui 基本忽略 accept 属性,ios safari 则严格依赖 mime 类型但扩展名支持差;正确写法需 mime+扩展名双写且无空格,禁用通配符,前端 js 必须校验文件扩展名和 magic bytes,服务端文件头校验不可省。

安卓 WebView 和 MIUI/EMUI 对 accept 属性基本忽略
很多安卓定制系统(如华为 EMUI、小米 MIUI)的 WebView 直接不解析 accept 属性,哪怕写成 accept="application/pdf,.pdf" 也毫无反应——文件选择框照常显示“所有文件”。这不是 bug,是它们对 HTML5 文件 API 的实现裁剪。iOS Safari 则相反:它严格依赖 MIME 类型,但对扩展名(如 .xlsx)支持极差,单写扩展名大概率失效。
accept 值必须 MIME + 扩展名双写,且逗号后不能有空格
只写 accept="image/png" 或只写 accept=".png" 都会掉兼容性坑里。正确写法是:
-
accept="image/png,image/jpeg,.png,.jpg"—— 显式覆盖常见变体,避免image/pjpeg被漏 -
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel,.xlsx,.xls"—— Excel 必须同时覆盖新旧格式 MIME 和扩展名 -
accept="text/csv,.csv"✅,accept="text/csv , .csv"❌(Safari 会丢弃整个属性)
别用 image/*、video/* 这类通配符,移动端卡顿+漏判
accept="image/*" 在 Chrome for Android 和 iOS Safari 上容易触发文件选择框延迟 6–10 秒,原因是浏览器试图枚举所有已知图片 MIME 类型并做匹配,底层实现未优化。更糟的是,image/* 会放行 .svg(可嵌脚本)、.psd(image/vnd.adobe.photoshop),根本不是你想要的“安全图片”。
实际做法是:
- 只列明确可信的子类型:
accept="image/png,image/jpeg,image/gif" - 避开模糊类型:
text/*会匹配text/html,上传后可能被服务端误执行 - 音频/视频同理,用
audio/mpeg,audio/wav,.mp3,.wav替代audio/*
前端 JS 必须补位校验,不能信 event.target.files[0].type
移动端用户选完文件后,event.target.files 里的 file.type 字段在安卓和 iOS 上都不可靠——重命名过的恶意文件(比如把 shell.php 改成 report.jpg)仍会返回 image/jpeg。必须立刻做两件事:
- 用
file.name.toLowerCase().match(/\.(png|jpg|pdf)$/i)做扩展名白名单比对 - 关键业务加 magic bytes 校验:用
FileReader读前 4 字节,PDF 是%PDF(25 50 44 46),PNG 是\x89PNG - multiple 场景下必须遍历全部
files,不能只检查第一个
真正棘手的点在于:即使你 JS 校验通过了,用户仍能用 DevTools 删除 accept、禁用 JS、或直接 curl 上传——所以服务端读文件头才是唯一可信依据,这点永远不能省。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











