手持证件照上传需前端约束:仅限JPEG/PNG格式、≤5MB、竖构图(高宽比>1.2),用Canvas加遮罩与提示文字预览,校验魔数防伪格式,兼容iOS EXIF旋转及Android WebView差异。

手持证件照上传需要哪些前端约束
用户上传手持证件照,核心不是“能传”,而是“传得对”。浏览器原生 <input type="file"> 不做内容校验,必须靠前端加限制:文件类型、大小、宽高比、甚至简单的人脸朝向提示。否则后端收到模糊、横拍、遮脸、反光的图,识别率归零,反复让用户重传,体验直接崩。
- 只接受
image/jpeg和image/png,拒绝image/gif(动图无意义)和image/webp(部分老安卓 WebView 不稳定解析) - 限制单文件 ≤ 5MB,用
input.files[0].size在change事件里即时判断 - 强制要求竖构图:上传前用
URL.createObjectURL()创建临时 URL,用<img>加载后读取naturalWidth/naturalHeight,比值height / width > 1.2才算合格(排除横屏自拍) - 展示区用固定宽高 +
object-fit: cover,避免拉伸变形
怎么用 Canvas 做实时预览与裁剪示意
纯 <img> 标签无法叠加文字水印或半透明遮罩层,而手持照通常要提示“请将证件举至胸前,人脸清晰可见”。Canvas 是最轻量可控的方案:
- 创建
<canvas width="300" height="400">,尺寸按证件照常用比例(如 3:4)设定 - 图片加载完成后,用
ctx.drawImage(img, 0, 0, canvas.width, canvas.height)绘制底图 - 再用
ctx.fillStyle = "rgba(0,0,0,0.5)"绘制深色遮罩,留出中央区域透出原图 - 最后用
ctx.font和ctx.fillText()加提示文字,比如“请举起身份证,确保头像和证件边缘完整”
注意:toDataURL() 导出时若图片过大,iOS Safari 可能触发内存警告;建议预览阶段只用 Canvas 渲染,不导出,真正提交时再用原文件二进制流上传。
后端接收时常见的 MIME 类型陷阱
前端设了 accept="image/jpeg,image/png",不代表后端一定能信。很多用户会手动改后缀名(如把 .jpg 改成 .png),或用截图工具保存为伪 PNG(实际是 JPEG 编码)。Node.js 的 multer、Python 的 Flask-Uploads 默认只看扩展名或 Content-Type 头,容易放行错误格式。
立即学习“前端免费学习笔记(深入)”;
- 必须用文件魔数(magic number)校验:读取文件前 4 字节,
FF D8 FF是 JPEG,89 50 4E 47是 PNG - Node.js 可用
file-type库,Python 推荐python-magic - 如果发现
Content-Type是image/png但魔数是 JPEG,应拒收并返回明确错误:"文件实际格式与扩展名不符,请勿修改后缀"
移动端拍照上传的兼容性雷区
iOS Safari 的 capture="environment" 能调后置摄像头,但 Android 各厂商 WebView 行为不一:部分国产浏览器忽略该属性,直接唤起相册;部分强制走系统相机但不支持闪光灯控制。
- 不要依赖
capture,统一用accept="image/*",并在 UI 上明确提示“建议使用后置摄像头拍摄” - 拍照后图片可能被旋转:iOS 默认写入 EXIF
Orientation,但 Canvas 绘制时不自动纠正,导致预览倒置。需用exif-js或piexifjs读取 orientation 值,并在绘制时用ctx.rotate()或翻转坐标系补偿 - 微信内置浏览器(X5 内核)对
input[type=file]的change事件触发有延迟,建议加防抖 + loading 状态锁,避免用户重复点击
手持证件照上传看似简单,真正卡住上线的,往往是 iOS 的 EXIF 旋转、Android 的魔数误判、还有用户拍完发现光线太暗却已点提交——这些细节没压住,后面所有 OCR 和审核逻辑都是空中楼阁。



















