notallowederror或notfounderror主因是环境与权限:必须https或localhost,禁用非用户手势调用,移动端需facingmode、playsinline等适配,video未就绪即绘制会导致黑图或模糊。

MediaDevices.getUserMedia() 调用失败的常见原因
直接调用 getUserMedia() 报错 “NotAllowedError” 或 “NotFoundError”,基本都和环境或权限有关。HTTPS 是硬性前提——本地开发用 http://localhost 可以绕过,但 http://127.0.0.1 或任何非 localhost 的 http 地址都会被浏览器拒绝。真机调试时尤其容易踩这个坑。
其他关键点:
- 用户未主动触发(比如放在页面加载时自动调用),必须由 click/tap 等用户手势触发
- 移动端 Safari 对
{ video: true }默认不启用前置摄像头,需显式加facingMode: 'user' - 部分安卓 WebView(如微信内置)不支持
getUserMedia(),得 fallback 到系统相机唤起
video 元素无法显示实时画面
拿到 MediaStream 后赋给 video.srcObject 却黑屏或报错 “InvalidStateError”,大概率是没等视频元数据加载完成就播放。不要在 then 里立刻 play(),要监听 loadeddata 或用 await video.play() 捕获 Promise 拒绝。
典型写法:
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
video.srcObject = stream;
await video.play().catch(e => console.warn('play failed:', e));
另外注意:video 元素必须设置 width/height 或 CSS 尺寸,否则可能渲染为 0×0;iOS Safari 还要求加 playsinline 属性,否则会全屏跳转。
canvas.toDataURL() 拍出黑图或模糊图
用 canvas.getContext('2d').drawImage(video, 0, 0) 后调 toDataURL() 得到纯黑图,说明 canvas 没成功捕获帧——最常见原因是 video 还没 ready,或 drawImage 时 video 尺寸/坐标超出了 canvas 范围。
安全做法:
- 确保
video.readyState === 4(HAVE_ENOUGH_DATA)再绘制 - 用
video.videoWidth/video.videoHeight动态设 canvas 尺寸,别硬编码 - 避免跨域视频源(比如把 video.src 设成远程地址),否则 canvas 会被污染,
toDataURL()抛 SecurityError
如果拍出来模糊,检查是否 canvas 宽高和 video 自然尺寸比例不一致导致拉伸;建议保持等比缩放,或用 imageSmoothingEnabled = false 关闭插值。
移动端唤起系统相机的兼容方案
当 getUserMedia() 不可用(如旧版微信、部分安卓 WebView),可退化为 <input type="file" accept="image/*" capture="environment">。其中 capture="environment" 在多数安卓浏览器中会直接打开后置摄像头,iOS Safari 则仍走相册选择,但至少能拍照上传。
注意点:
-
capture值可选"user"(前置)、"environment"(后置),但不是所有 UA 都识别 - 触发后得到的是
File对象,需用FileReader.readAsDataURL()转成 base64 显示 - 不能像 MediaStream 那样实时预览,属于“拍完即传”的离线流程
真正复杂的点在于混合策略:既要检测 getUserMedia 支持性,又要监听降级 input 的 change 事件,还得统一处理图片方向(EXIF orientation)、压缩、上传逻辑——这些细节一旦漏掉,用户在不同机型上体验差异极大。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











