UniApp 多端人脸认证图片上传实现

发布于:2025-07-18 ⋅ 阅读:(18) ⋅ 点赞:(0)

UniApp 多端人脸认证图片上传实现(H5 + 非 H5)

本文简洁说明如何用 UniApp 实现跨端(H5、小程序、App)人脸认证图片的拍摄、处理与上传,核心是兼容不同平台的差异点。

核心功能与流程
  1. 调用前置摄像头拍摄人脸照片
  2. 图片压缩处理(H5 端需额外处理,非 H5 端直接使用原生能力)
  3. 上传至后端接口进行认证
  4. 根据认证结果执行后续操作
关键差异点说明

在这里插入图片描述

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 });
}
使用说明
  1. 代码通过#ifdef H5和#ifndef H5区分平台逻辑,无需额外修改
  2. 需确保HTTP_REQUEST_URL(后端接口地址)、TOKENNAME(令牌键名)已定义
  3. handleSave方法为认证成功后的后续操作,需根据业务实现
  4. dataURLtoBlob是 H5 端必须的辅助方法,用于 base64 转文件格式

网站公告

今日签到

点亮在社区的每一天
去签到