用<input type="file">上传视频需配合FileReader预览、三重校验(大小/时长/格式)、FormData正确构造及移动端capture适配,才能解决无反馈、卡顿、格式误判等问题。

直接用 <input type="file"> 就能上传视频,但只写这行 HTML 远远不够——用户选完文件没反馈、大视频卡死、格式被拒、移动端拍完传不上去,这些问题全在「怎么配」和「怎么接」里。
video 标签预览 + input file 基础绑定
用户需要立刻看到自己选了什么,而不是盲传。必须用 FileReader 把本地文件转成 URL 给 <video> 的 src:
const input = document.querySelector('input[type="file"]');<br>const video = document.querySelector('video');<br><br>input.addEventListener('change', (e) => {<br> const file = e.target.files[0];<br> if (!file || !file.type.startsWith('video/')) return;<br> const url = URL.createObjectURL(file);<br> video.src = url;<br> video.load(); // 触发元信息加载<br>});-
file.type比扩展名可靠,file.type.startsWith('video/')能覆盖 mp4、mov、webm 等主流类型 - 别漏掉
video.load(),否则duration可能为NaN,后续时长校验就失效 - 用完记得调
URL.revokeObjectURL(url)防内存泄漏,尤其在频繁切换文件时
限制大小、时长、格式的三道关卡
前端校验不是摆设,它能立刻拦截明显不合格的文件,避免白跑一次请求:
- 大小:检查
file.size > 500 * 1024 * 1024(500MB),超了直接alert('文件不能超过 500MB') - 时长:等
video.readyState === 4后读video.duration,注意 Safari 下可能异步延迟,加个setTimeout容忍 1s - 格式:仅靠
accept="video/*"不够,iOS 拍摄的 MOV 文件在部分安卓浏览器里会报成video/mp4,所以得结合file.name.split('.').pop().toLowerCase()辅助判断
上传失败最常卡在 enctype 和 FormData 构造上
后端收不到文件?90% 是前端没把数据包对。重点盯死这两处:
立即学习“前端免费学习笔记(深入)”;
-
<form>必须带enctype="multipart/form-data",且 method 为POST;如果用fetch,必须用FormData实例,不能手动拼 body -
FormData.append('video', file)的 key(这里是'video')必须和后端约定一致,PHP 用$_FILES['video'],Node.js Koa 用ctx.request.files.video - 如果后端要求带 token 或签名,不要塞进
FormData,而要放在headers里,例如:{ headers: { Authorization: 'Bearer xxx' } }
移动端 H5 拍摄视频上传的隐藏坑
用户点「拍摄」后传上来一堆黑屏、无声、时长为 0 的文件,问题往往出在 capture 属性和 MIME 类型协商上:
- 强制调用摄像头:用
<input type="file" accept="video/*" capture="environment">,environment指后置摄像头,user是前置 - iOS Safari 拍摄的 MOV 文件,
file.type常为空字符串,此时只能依赖file.name后缀或服务端二次探测 - 某些安卓 WebView 对
capture支持不全,降级方案是去掉该属性,改用accept="video/*;capture=camcorder"(非标准但部分生效)
真正难的不是“怎么传”,而是“传之前怎么筛”和“传失败时怎么告诉用户”。后端返回的 400 Bad Request 如果只说「文件不合法」,前端就得自己拆解错误码映射到具体原因——比如是编码不支持、还是分片丢失、或是签名过期。这些边界情况,才是决定上传体验是否「像原生 App」的关键。



















