微信小程序学习实录12:wx.serviceMarket.invokeService接口OCR识别营业执照和银行卡

wxml文件

html 复制代码
<!-- ocr-page.wxml -->
<view class="ocr-container">
    <!-- 营业执照识别区域 -->
    <view class="ocr-module">
        <view class="module-title">营业执照识别</view>
        <!-- 表单:自动填充公司名称、信用代码、法人代表 -->
        <form class="ocr-form">
            <view class="form-item">
                <label class="form-label">公司名称</label>
                <input class="form-input" placeholder="请识别营业执照自动填充" value="{{bizInfo.companyName}}" disabled />
            </view>
            <view class="form-item">
                <label class="form-label">统一信用代码</label>
                <input class="form-input" placeholder="请识别营业执照自动填充" value="{{bizInfo.creditCode}}" disabled />
            </view>
            <view class="form-item">
                <label class="form-label">法人代表</label>
                <input class="form-input" placeholder="请识别营业执照自动填充" value="{{bizInfo.legalPerson}}" disabled />
            </view>
        </form>
        <!-- 识别按钮 -->
        <button class="ocr-btn" bindtap="recognizeBusinessLicense">点击识别营业执照</button>
    </view>

    <!-- 分割线 -->
    <view class="divider"></view>

    <!-- 银行卡识别区域 -->
    <view class="ocr-module">
        <view class="module-title">银行卡识别</view>
        <!-- 表单:自动填充银行卡号 -->
        <form class="ocr-form">
            <view class="form-item">
                <label class="form-label">银行卡号</label>
                <input class="form-input" placeholder="请识别银行卡自动填充" value="{{bankInfo.cardNumber}}" disabled />
            </view>
        </form>
        <!-- 识别按钮 -->
        <button class="ocr-btn" bindtap="recognizeBankCard">点击识别银行卡</button>
    </view>
</view>

js文件

javascript 复制代码
// ocr-page.js
Page({
  /**
   * 页面初始数据
   */
  data: {
    // 营业执照识别结果(用于自动填充)
    bizInfo: {
      companyName: '', // 公司名称
      creditCode: '', // 统一信用代码
      legalPerson: '' // 法人代表
    },
    // 银行卡识别结果(用于自动填充)
    bankInfo: {
      cardNumber: '' // 银行卡号
    }
  },

  /**
   * 公共方法:图片临时路径转Base64(Promise封装,统一异常处理)
   * @param {string} tempImagePath 图片临时文件路径
   * @returns {Promise<string>} Base64字符串
   */
  convertImageToBase64(tempImagePath) {
    return new Promise((resolve, reject) => {
      if (!tempImagePath) {
        reject(new Error('图片路径无效'));
        return;
      }
      const fs = wx.getFileSystemManager();
      try {
        const base64Str = fs.readFileSync(tempImagePath, 'base64');
        // 校验Base64结果有效性
        if (!base64Str || typeof base64Str !== 'string') {
          reject(new Error('图片转Base64失败,结果为空或非字符串'));
          return;
        }
        resolve(base64Str);
      } catch (err) {
        reject(new Error(`图片读取失败:${err.message || '未知错误'}`));
      }
    });
  },

  /**
   * 营业执照识别:点击按钮触发,识别后自动填充表单
   */
  recognizeBusinessLicense() {
    const that = this;
    wx.chooseMedia({
      count: 1, // 仅选择1张图片
      sizeType: ['original', 'compressed'], // 支持原图/压缩图
      sourceType: ['camera', 'album'], // 支持拍照/相册选择
      mediaType: ['image'], // 明确只选择图片,避免视频导致的错误
      success: async (res) => {
        try {
          // 优化1:安全校验tempFiles,防止取值失败
          if (!res.tempFiles || res.tempFiles.length === 0) {
            wx.showToast({
              title: '未获取到有效图片',
              icon: 'none'
            });
            return;
          }
          const tempImagePath = res.tempFiles[0].tempFilePath;
          wx.showLoading({
            title: '识别中...',
            mask: true
          });

          // 优化2:调用公共方法转Base64,async/await更易读
          const base64Str = await that.convertImageToBase64(tempImagePath);

          // 调用服务市场OCR接口
          wx.serviceMarket.invokeService({
            service: 'wx79ac3de8be320b71',
            api: 'OcrAllInOne',
            data: {
              data_type: 2,
              ocr_type: 7, // 7对应营业执照识别
              img_data: base64Str // 确保base64Str非空(公共方法已校验)
            },
            success(res) {
              wx.hideLoading();
              console.log('营业执照识别结果:', res);
              // 优化3:安全获取OCR结果,多层兜底为空对象
              const ocrResult = res.data ?? res ?? {};
              // 优化4:严谨校验ocrResult有效性(排除null、数组)
              if (typeof ocrResult === 'object' && ocrResult !== null && !Array.isArray(ocrResult)) {
                // 优化5:可选链安全访问深层属性,兜底为空字符串
                const companyName = ocrResult?.biz_license_res?.enterprise_name?.text || '';
                const creditCode = ocrResult?.biz_license_res?.reg_num?.text || '';
                const legalPerson = ocrResult?.biz_license_res?.legal_representative?.text || '';
                // 批量设置数据
                that.setData({
                  'bizInfo.companyName': companyName,
                  'bizInfo.creditCode': creditCode,
                  'bizInfo.legalPerson': legalPerson
                });
                wx.showToast({
                  title: '营业执照识别成功',
                  icon: 'success'
                });
              } else {
                wx.showToast({
                  title: '未识别到营业执照信息',
                  icon: 'none'
                });
              }
            },
            fail(err) {
              wx.hideLoading();
              console.error('营业执照识别接口调用失败:', err);
              wx.showToast({
                title: '识别失败,请检查图片',
                icon: 'none'
              });
            }
          });
        } catch (err) {
          wx.hideLoading();
          console.error('营业执照识别流程异常:', err);
          wx.showToast({
            title: err.message || '识别流程出错,请重试',
            icon: 'none'
          });
        }
      },
      fail(err) {
        console.error('选择图片失败:', err);
        wx.showToast({
          title: '取消图片选择',
          icon: 'none'
        });
      }
    });
  },

  /**
   * 银行卡识别:点击按钮触发,自动填充银行卡号
   */
  recognizeBankCard() {
    const that = this;
    wx.chooseMedia({
      count: 1,
      sizeType: ['original', 'compressed'],
      sourceType: ['camera', 'album'],
      mediaType: ['image'], // 明确只选择图片
      success: async (res) => {
        try {
          // 优化1:安全校验tempFiles,防止取值失败
          if (!res.tempFiles || res.tempFiles.length === 0) {
            wx.showToast({
              title: '未获取到有效图片',
              icon: 'none'
            });
            return;
          }
          const tempImagePath = res.tempFiles[0].tempFilePath;
          wx.showLoading({
            title: '识别中...',
            mask: true
          });

          // 优化2:调用公共方法转Base64,统一异常处理
          const base64Str = await that.convertImageToBase64(tempImagePath);

          // 调用银行卡OCR识别接口
          wx.serviceMarket.invokeService({
            service: 'wx79ac3de8be320b71',
            api: 'OcrAllInOne',
            data: {
              data_type: 2,
              ocr_type: 2, // 银行卡识别类型
              img_data: base64Str // 公共方法已确保非空
            },
            success(res) {
              wx.hideLoading();
              console.log('银行卡识别结果:', res);
              // 优化3:安全获取OCR结果,兜底为空对象
              const ocrResult = res.data ?? res ?? {};
              // 优化4:严谨校验ocrResult有效性
              if (typeof ocrResult === 'object' && ocrResult !== null && !Array.isArray(ocrResult)) {
                // 优化5:可选链安全访问深层属性,兜底为空字符串
                const cardNumber = ocrResult?.bankcard_res?.number?.text || '';
                that.setData({
                  'bankInfo.cardNumber': cardNumber
                });
                wx.showToast({
                  title: '银行卡识别成功',
                  icon: 'success'
                });
              } else {
                wx.showToast({
                  title: '未识别到银行卡信息',
                  icon: 'none'
                });
              }
            },
            fail(err) {
              wx.hideLoading();
              console.error('银行卡识别接口调用失败:', err);
              wx.showToast({
                title: '识别失败,请检查图片',
                icon: 'none'
              });
            }
          });
        } catch (err) {
          wx.hideLoading();
          console.error('银行卡识别流程异常:', err);
          wx.showToast({
            title: err.message || '识别流程出错,请重试',
            icon: 'none'
          });
        }
      },
      fail(err) {
        console.error('选择图片失败:', err);
        wx.showToast({
          title: '取消图片选择',
          icon: 'none'
        });
      }
    });
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {
    this.showShare();
  },
  /**
   * 开启朋友圈分享功能
   *  监听路由切换/自动执行
   */
  showShare() {
    wx.showShareMenu({
      withShareTicket: true,
      menus: ['shareAppMessage', 'shareTimeline']
    })
  }
})

wx.serviceMarket.invokeService 专业解析

wx.serviceMarket.invokeService 接口,这是微信小程序服务市场的核心调用 API,以下从专业角度全面解析其使用方式、核心参数、代码中的实践要点及关键特性:

一、 接口核心定位

wx.serviceMarket.invokeService 是微信小程序官方提供的服务市场调用接口,用于在小程序内调用微信服务市场中已上架的第三方服务或官方标准化服务(如代码中的OCR文字识别服务),无需开发者自行搭建复杂后台能力,可快速集成各类成熟服务(OCR、人脸识别、短信发送、数据统计等)。

二、 核心参数解析(结合代码实践)

代码中完整使用了该接口的核心参数,各参数含义及使用要点如下:

参数名 必选 代码中的实践值 核心说明
service wx79ac3de8be320b71 服务市场中目标服务的服务ID(对应OCR全能识别服务的唯一标识),需在微信服务市场开通对应服务后获取,不可随意变更
api OcrAllInOne 该服务下的具体接口名(此处为OCR全能识别的统一接口名,不同服务的接口名由服务提供方定义,需参考对应服务文档)
data {data_type: 2, ocr_type: 7/2, img_data: base64Str} 传递给目标服务的业务参数 ,格式由对应API接口定义: 1. data_type: 2:指定传入的图片格式为Base64编码(1为url格式,代码中采用Base64更稳定); 2. ocr_type: 7(营业执照)/2(银行卡):指定OCR识别的具体类型,区分不同业务场景; 3. img_data: base64Str:图片Base64字符串(由公共方法convertImageToBase64转换而来,已做有效性校验)
success 回调函数 服务调用成功后的回调:接收服务返回的res数据,代码中在此处解析OCR识别结果、更新页面数据、提示用户操作成功
fail 回调函数 服务调用失败后的回调(如接口超时、权限不足、图片无效等):代码中在此处隐藏加载提示、打印错误日志、给用户友好提示

三、 代码中的最佳实践

  1. 完整的异常处理链路

    代码中为invokeService构建了多层异常兜底:

    • 接口自身的fail回调:捕获服务调用直接失败(如接口不可用、参数格式错误);
    • 外层try/catch:捕获await convertImageToBase64的异常及回调内部的非接口级异常;
    • 加载状态统一管理:调用前wx.showLoading,成功/失败/异常时均执行wx.hideLoading,避免加载状态挂起;
    • 用户友好提示:不同失败场景返回不同提示文案(如"识别失败,请检查图片""未识别到营业执照信息"),提升用户体验。
  2. 安全的数据解析策略

    success回调中,针对服务返回数据做了多重安全校验,避免深层属性取值报错:

    • 兜底赋值:const ocrResult = res.data ?? res ?? {},优先取res.data(服务返回核心数据),兜底为空对象;
    • 类型校验:typeof ocrResult === 'object' && ocrResult !== null && !Array.isArray(ocrResult),排除非对象类型的无效数据;
    • 可选链访问:ocrResult?.biz_license_res?.enterprise_name?.text || '',避免某一层属性不存在导致的程序报错,同时兜底为空字符串。
  3. 与异步流程的完美结合

    代码中使用async/await处理convertImageToBase64的异步转换,相比传统回调嵌套,代码可读性更强、流程更清晰;同时将invokeService(回调式API)嵌入async函数中,实现了异步流程的统一管理,确保图片转Base64完成后再调用OCR服务,避免数据传递异常。

  4. 参数规范化传递

    严格遵循服务接口的参数要求:

    • 明确data_type: 2,与传入的base64Str格式匹配;
    • 区分ocr_type的取值(7对应营业执照、2对应银行卡),精准调用对应OCR识别能力;
    • 确保img_data非空(由convertImageToBase64方法做前置校验),避免因无效参数导致服务调用失败。

四、 关键注意事项(基于代码延伸)

  1. 服务开通前置条件 :使用该接口前,需在微信小程序后台「服务市场」中开通对应服务(代码中的wx79ac3de8be320b71对应OCR服务),部分服务可能需要付费或申请权限;
  2. 权限配置:无需额外配置小程序权限,但需确保小程序已发布(开发版可正常调试,体验版/正式版需符合微信审核规范);
  3. 图片格式限制 :代码中通过wx.chooseMedia限制mediaType: ['image'],避免传入视频导致转换失败,同时支持原图/压缩图,兼顾识别精度和传输效率;
  4. 异常日志打印 :代码中在failcatch中均打印了详细错误日志(console.error),便于线上问题排查,这是生产环境开发的必备实践。

总结

  1. wx.serviceMarket.invokeService 是小程序集成第三方/官方服务的核心API,核心用于调用服务市场的标准化能力;
  2. 核心必填参数为service(服务ID)、api(接口名)、data(业务参数),success/fail用于处理回调结果;
  3. 代码中的实践充分体现了"异常兜底、安全取值、异步统一、用户友好"的最佳开发规范,可作为该接口的参考使用模板;
  4. 使用前需开通对应服务,参数传递需严格遵循服务文档要求,同时做好异步流程和加载状态的管理。

@漏刻有时

相关推荐
漏刻有时14 小时前
微信小程序学习实录13:网络PDF文件的下载、本地缓存、预览、保存及主动转发
网络·学习·微信小程序
毛小茛14 小时前
芋道管理系统学习——简介
学习
走在路上的菜鸟14 小时前
Android学Flutter学习笔记 第三节 Android视角认知Flutter(触摸事件,List,Text,Input)
android·学习·flutter
好奇龙猫14 小时前
【大学院-筆記試験練習:数据库(データベース問題訓練) と 软件工程(ソフトウェア)(8)】
学习
石像鬼₧魂石14 小时前
ettercap 命令执行输出的详细解读
linux·学习
Century_Dragon14 小时前
以赛促教,赋能课堂:智能网联汽车仿真教学解决方案
学习
曾浩轩14 小时前
跟着江协科技学STM32之4-2OLED显示屏
c语言·stm32·单片机·嵌入式硬件·学习
航Hang*14 小时前
第八章:综合布线技术 —— 进线间和建筑群子系统设计
网络·笔记·学习·设计·期末·光纤
知识分享小能手14 小时前
Ubuntu入门学习教程,从入门到精通, Ubuntu 22.04中的C/C++编程(18)
c语言·学习·ubuntu