accept属性仅是UI提示,无法阻止非法文件上传;必须依赖后端通过文件头(magic bytes)校验真实类型,前端可辅以file.name后缀判断和change事件检查。

用 accept 属性限制并声明可选文件类型
浏览器原生支持通过 accept 属性缩小用户可选文件范围,它不校验文件内容,只影响文件选择器弹窗中默认显示的文件类型。常见写法有:
-
accept="image/*":显示所有图片(.png、.jpg、.webp 等) -
accept=".pdf,.docx":仅显示后缀匹配的文件(注意点号不能省) -
accept="application/pdf":按 MIME 类型过滤(但部分系统对 MIME 识别不准,兼容性弱于后缀) -
accept="image/png, image/jpeg":多个 MIME 类型用英文逗号分隔
⚠️ 注意:accept 是纯 UI 提示,完全可被绕过(比如手动改后缀、拖拽文件),**绝不能代替服务端校验**。
用 JavaScript 读取用户实际选中的 file.type
选中文件后,event.target.files[0].type 返回浏览器根据文件头或扩展名推测的 MIME 类型。但这个值不可靠:
- 空字符串很常见(如上传 .txt 或自定义后缀文件时)
- 用户改过后缀会导致
type错误(比如把 .exe 改成 .jpg,type可能变成image/jpeg) - 不同浏览器对同一文件返回的
type可能不同(尤其是 Office 文档)
所以 file.type 适合做轻量级提示(如“你选的是个图片”),但不适合做判断依据。真正需要类型判断时,应结合 file.name 后缀 + 服务端二进制检测。
立即学习“前端免费学习笔记(深入)”;
用 file.name 提取后缀做基础过滤
比 file.type 更稳定的是从文件名里解析后缀:
const ext = file.name.split('.').pop().toLowerCase();
if (['jpg', 'jpeg', 'png', 'gif'].includes(ext)) {
// 视为图片
}
这个方法简单、跨浏览器一致,但仍有风险:
- 文件名无后缀(如
report)会得到空字符串 - 路径中含点号(如
/home/user/my.file.txt)会被错误截断 —— 实际上file.name只含最终文件名,不含路径,这点是安全的
建议始终用 file.name 而非 input.value 获取名称,因为后者在某些浏览器中返回完整路径(已废弃)或空字符串。
为什么不能依赖 input.value 获取文件名或类型
input.value 在现代浏览器中已被刻意弱化:
- Chrome/Firefox/Safari 均只返回伪路径(如
C:\fakepath\photo.jpg)或空字符串 - 它不反映真实文件系统路径,也无法从中可靠提取类型或后缀
- 规范明确要求 UA(用户代理)不得暴露本地路径,这是安全策略,不是 bug
所以任何基于 input.value 的逻辑都应立即替换为监听 change 事件 + 访问 event.target.files。
最易被忽略的一点:前端类型限制只是用户体验优化手段,真正的类型判定必须落在服务端——读取文件魔数(magic bytes)才是唯一可信方式。前端做的所有检查,都只是防止用户误操作的“减速带”,不是“防火墙”。



















