UniApp 多端人脸认证图片上传实现(H5 + 非 H5)
本文简洁说明如何用 UniApp 实现跨端(H5、小程序、App)人脸认证图片的拍摄、处理与上传,核心是兼容不同平台的差异点。
核心功能与流程
- 调用前置摄像头拍摄人脸照片
- 图片压缩处理(H5 端需额外处理,非 H5 端直接使用原生能力)
- 上传至后端接口进行认证
- 根据认证结果执行后续操作
关键差异点说明
chooseImagefile(params) {
let that = this;
// 调用前置摄像头拍摄(限制1张,仅相机拍摄)
uni.chooseImage({
count: 1,
sourceType: ["camera"],
camera: "front",
success: (resFile) => {
const tempFilePath = resFile.tempFilePaths[0];
// #ifdef H5
// H5端:图片压缩+格式处理
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
// 获取图片信息(尺寸等)
uni.getImageInfo({
src: tempFilePath,
success: (imageInfo) => {
const originalWidth = imageInfo.width;
const originalHeight = imageInfo.height;
// 按比例调整尺寸(限制最大1080px,最小640px)
let targetWidth = originalWidth;
let targetHeight = originalHeight;
const MAX_WIDTH = 1080;
const MIN_WIDTH = 640;
if (targetWidth > MAX_WIDTH) {
targetHeight = Math.round((MAX_WIDTH / targetWidth) * targetHeight);
targetWidth = MAX_WIDTH;
} else if (targetWidth < MIN_WIDTH) {
targetHeight = Math.round((MIN_WIDTH / targetWidth) * targetHeight);
targetWidth = MIN_WIDTH;
}
// 设置canvas尺寸并绘制图片
canvas.width = targetWidth;
canvas.height = targetHeight;
const img = new Image();
img.crossOrigin = "anonymous"; // 解决跨域
img.src = tempFilePath;
img.onload = () => {
ctx.drawImage(img, 0, 0, targetWidth, targetHeight);
// 转为base64并压缩(质量0.8)
const compressedBase64 = canvas.toDataURL("image/jpeg", 0.8);
// base64转Blob再转File
const blob = this.dataURLtoBlob(compressedBase64);
const file = new File([blob], `face_${Date.now()}.jpg`, { type: "image/jpeg" });
// H5用fetch上传(不支持uni.uploadFile传File)
const formData = new FormData();
formData.append("file", file);
formData.append("name", params.name);
formData.append("idCard", params.idCard);
uni.showLoading({ title: "认证中...", mask: true });
fetch(`${HTTP_REQUEST_URL}/api/v1/auth/faceAuth`, {
method: "POST",
headers: { Authorization: that.token },
body: formData
})
.then(res => res.json())
.then(data => {
uni.hideLoading();
if (data.code === 200 && data.data.auth) {
params.faceUrl = data.data.faceUrl;
that.handleSave(params); // 认证成功,执行保存
} else {
uni.showToast({ title: "人脸认证失败,请重新拍摄", icon: "none" });
}
})
.catch(err => {
uni.hideLoading();
uni.showToast({ title: "上传失败,请重试", icon: "none" });
console.error("H5上传失败:", err);
});
};
},
fail: err => {
uni.showToast({ title: "获取图片信息失败", icon: "none" });
console.error("getImageInfo失败:", err);
}
});
// #endif
// #ifndef H5
// 非H5端(小程序/App)直接上传
uni.showLoading({ title: "认证中...", mask: true });
uni.uploadFile({
url: `${HTTP_REQUEST_URL}/api/v1/auth/faceAuth`,
filePath: tempFilePath, // 直接用本地文件路径
name: "file",
formData: { name: params.name, idCard: params.idCard },
header: { "Content-Type": "multipart/form-data", [TOKENNAME]: that.token },
success: res => {
uni.hideLoading();
try {
const data = JSON.parse(res.data);
if (data.code === 200 && data.data.auth) {
params.faceUrl = data.data.faceUrl;
that.handleSave(); // 认证成功,执行保存
} else {
uni.showToast({ title: "人脸认证失败,请重新拍摄", icon: "none" });
}
} catch (e) {
uni.showToast({ title: "数据解析失败", icon: "none" });
}
},
fail: err => {
uni.hideLoading();
uni.showToast({ title: "上传失败,请重试", icon: "none" });
console.error("上传失败:", err);
}
});
// #endif
},
fail: err => {
uni.showToast({ title: "拍照失败", icon: "none" });
console.error("拍照失败:", err);
}
});
},
// 辅助方法:base64转Blob(H5端用)
dataURLtoBlob(dataurl) {
const arr = dataurl.split(',');
const mime = arr[0].match(/:(.*?);/)[1];
const bstr = atob(arr[1]);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
}
使用说明
- 代码通过#ifdef H5和#ifndef H5区分平台逻辑,无需额外修改
- 需确保HTTP_REQUEST_URL(后端接口地址)、TOKENNAME(令牌键名)已定义
- handleSave方法为认证成功后的后续操作,需根据业务实现
- dataURLtoBlob是 H5 端必须的辅助方法,用于 base64 转文件格式