赞
踩
开发上传卡证功能时,必须要鉴别上传的图片,否则功能相当于废的;至于为什么选择百度云,那是因为阿里云又贵又难用,百度云的免费额度更多,并且更成熟专业;且针对于用户的角度,两者没有太大的使用区别,只需要追求一个稳定的服务即可。
开发场景:uniapp
-> 微信小程序
access_token
;token
调用鉴别接口;/* 引入封装接口 */ import { user_profile_baidu } from '@/utils/request/api.js'; /** * 定义百度云账号数据,用于获取鉴权 Token * @BAIDU_PROFILE { @grant_type 必填项,值为 client_credentials @client_id 必填项,值为百度云应用的 Api-Key @client_secret 必填项,值为百度云应用的 Secret-Key } */ const BAIDU_PROFILE = { grant_type: 'client_credentials', client_id: '你的应用 API-Key', client_secret: '你的应用 Secret-Key' } /** * 定义百度云鉴别种类接口 * @BAIDU_REQUEST_API 百度云鉴别请求接口 * @BAIDU_LICENSE_API 营业执照鉴别接口 * @BAIDU_IDCARD_API 身份证鉴别接口 */ let BAIDU_REQUEST_API const BAIDU_LICENSE_API = 'https://aip.baidubce.com/rest/2.0/ocr/v1/business_license' const BAIDU_IDCARD_API = 'https://aip.baidubce.com/rest/2.0/ocr/v1/idcard' /** * 定义百度云鉴别接口参数 * @BAIDU_BUSSINESS_PARAMS Base64 | 营业执照鉴别参数 { image: 二进制文件流 } * @BAIDU_IDCARD_PARAMS Base64 && String | 身份证鉴别参数 { image: 二进制文件流 id_card_side: 'front'-正面, 'back'-反面 } */ const BAIDU_BUSSINESS_PARAMS = { image: '' } const BAIDU_IDCARD_PARAMS = { image: '', id_card_side: '' } /** * 设置缓存时间 * @params { @key String | 缓存键 @value Object | 缓存值 @seconds Number | 缓存时间 } */ const Storage = (key, value, seconds = 3600 * 24 * 29) => { let nowTime = Date.parse(new Date()) / 1000; if (key && value) { let expire = nowTime + Number(seconds); uni.setStorageSync(key, value + '|' +expire) } else if (key && !value) { let val = uni.getStorageSync(key); if (val) { // 缓存存在,判断是否过期 let temp = val.split('|') if (!temp[1] || temp[1] <= nowTime) { uni.removeStorageSync(key) return ''; } else { return temp[0]; } } } } /** * 错误处理函数 * @params { @type String | 识别类型 { 'license'-营业执照, 'card'-身份证正面, 'card2'-身份证反面 } @err Object | 判断的数据源 } */ const ErrExcept = (type, err) => { // 判断数据错误情况 switch(type) { case 'license': if (err.data.error_code) { // 判断常规错误情况 switch(err.data.error_code) { case 1,2,4: uni.$u.toast('识别失败,服务器错误') break; case 17,18,19: uni.$u.toast('识别失败,资源超额') break; default: uni.$u.toast('识别失败,请检查图片') break; } throw new Error('server error') } break; case 'card': if (err.data.image_status != 'normal') { uni.$u.toast('识别失败,请重新上传正确的证件照!') throw new Error('image error') } break; case 'card2': if (err.data.image_status != 'normal') { uni.$u.toast('识别失败,请重新上传正确的证件照!') throw new Error('image error') } break; default: uni.$u.toast('上传成功'); } } /* 获取 access_token */ export const GET_ACCESS_TOKEN = () => { return new Promise((resolve, reject) => { try{ let access_token = Storage('access_token'); if (!access_token || access_token == '') { user_profile_baidu(BAIDU_PROFILE).then(res => { access_token = res.data.access_token; Storage('access_token', access_token) resolve(access_token) }) } else { resolve(access_token) } }catch(e){ //TODO handle the exception reject(e) } }) } /** * 百度云识别证件函数 * @params { @type Number | 本地上传图片的途径 { 0-拍照, 1-相册 } @apiName String | 识别证件类型 { 'license'-营业执照, 'card'-身份证正面, 'card2'-身份证反面 } @token | access_token } */ export const BAIDU_OCR = (type, apiName, token) => { return new Promise((resolve, reject) => { let pic = uni.chooseImage({ sizeType: ['compressed'], count: 1, sourceType: type == 0 ? 'camera' : 'album', success(res) { uni.getFileSystemManager().readFile({ filePath: res.tempFilePaths[0], encoding: 'base64', success(file) { uni.showLoading({title: '识别中'}) let baidu_data; // 定义请求的数据 if (apiName == 'license') { BAIDU_REQUEST_API = BAIDU_LICENSE_API baidu_data = BAIDU_BUSSINESS_PARAMS } else { BAIDU_REQUEST_API = BAIDU_IDCARD_API baidu_data = BAIDU_IDCARD_PARAMS if (apiName == 'card') { baidu_data.id_card_side = 'front' } else { baidu_data.id_card_side = 'back' } } baidu_data.image = file.data uni.request({ url: `${BAIDU_REQUEST_API}?access_token=${token}`, method: 'POST', header: { 'content-type': 'application/x-www-form-urlencoded' }, data: baidu_data, success(baidu_res) { uni.hideLoading() ErrExcept(apiName, baidu_res) resolve(res.tempFilePaths[0]) }, fail(baidu_res_reject) { uni.hideLoading() uni.$u.toast('识别失败,请重新上传') reject(baidu_res_reject) } }) }, fail(baidu_reject) { uni.$u.toast('读取失败,请重新上传') reject(baidu_reject) } }) }, fail: (err) => { uni.$u.toast('获取照片失败,请重新上传') reject(err) } }) }) }
个人 | 企业 |
---|---|
200次/月 | 2000次/月 |
API Key
和Secret Key
;access_token 是百度云服务器返回给你代码的鉴权加密串,需要将上文获取到的
API Key
和Secret Key
以get
明文请求方式发送,我们知道get
请求会把参数拼接在请求路径里面,容易导致密钥信息泄露;另外,前端获取加密串的时候,会经常性的提示 access_token 已过期,也无法经常保证程序的可用性,用户体验极差。所以为了保持密钥信息的安全性,最好是交由后端请求获取 access_token,处理完之后再递给前端。
access_token 有效期是30天,我们封装一个本地存储函数,定时清除 access_token。
/* 引入封装接口 */ import { user_profile_baidu } from '@/utils/request/api.js'; /** * 定义百度云账号数据,用于获取鉴权 Token * @BAIDU_PROFILE { @grant_type 必填项,值为 client_credentials @client_id 必填项,值为百度云应用的 Api-Key @client_secret 必填项,值为百度云应用的 Secret-Key } */ const BAIDU_PROFILE = { grant_type: 'client_credentials', client_id: '你的应用 API-Key', client_secret: '你的应用 Secret-Key' } /** * 设置缓存时间 * @params { @key String | 缓存键 @value Object | 缓存值 @seconds Number | 缓存时间 } */ const Storage = (key, value, seconds = 3600 * 24 * 29) => { let nowTime = Date.parse(new Date()) / 1000; if (key && value) { let expire = nowTime + Number(seconds); uni.setStorageSync(key, value + '|' +expire) } else if (key && !value) { let val = uni.getStorageSync(key); if (val) { // 缓存存在,判断是否过期 let temp = val.split('|') if (!temp[1] || temp[1] <= nowTime) { uni.removeStorageSync(key) return ''; } else { return temp[0]; } } } } /* 获取 access_token,这里 export 出去是因为 access_token在别处还有用到 */ export const GET_ACCESS_TOKEN = () => { return new Promise((resolve, reject) => { try{ let access_token = Storage('access_token'); if (!access_token || access_token == '') { // user_profile_baidu是自封装请求函数 user_profile_baidu(BAIDU_PROFILE).then(res => { access_token = res.data.access_token; Storage('access_token', access_token) resolve(access_token) }) } else { resolve(access_token) } }catch(e){ //TODO handle the exception reject(e) } }) }
在应用列表页点击管理,进入详情页,点击展开,获取功能接口:
/** * 定义百度云鉴别种类接口 * @BAIDU_REQUEST_API 百度云鉴别请求接口 * @BAIDU_LICENSE_API 营业执照鉴别接口 * @BAIDU_IDCARD_API 身份证鉴别接口 */ let BAIDU_REQUEST_API const BAIDU_LICENSE_API = 'https://aip.baidubce.com/rest/2.0/ocr/v1/business_license' const BAIDU_IDCARD_API = 'https://aip.baidubce.com/rest/2.0/ocr/v1/idcard' /** * 定义百度云鉴别接口参数 * @BAIDU_BUSSINESS_PARAMS Base64 | 营业执照鉴别参数 { image: 二进制文件流 } * @BAIDU_IDCARD_PARAMS Base64 && String | 身份证鉴别参数 { image: 二进制文件流 id_card_side: 'front'-正面, 'back'-反面 } */ const BAIDU_BUSSINESS_PARAMS = { image: '' } const BAIDU_IDCARD_PARAMS = { image: '', id_card_side: '' } /** * 错误处理函数 * @params { @type String | 识别类型 { 'license'-营业执照, 'card'-身份证正面, 'card2'-身份证反面 } @err Object | 判断的数据源 } */ const ErrExcept = (type, err) => { // 判断数据错误情况 switch(type) { case 'license': if (err.data.error_code) { // 判断常规错误情况 switch(err.data.error_code) { case 1,2,4: uni.$u.toast('识别失败,服务器错误') break; case 17,18,19: uni.$u.toast('识别失败,资源超额') break; default: uni.$u.toast('识别失败,请检查图片') break; } throw new Error('server error') } break; case 'card': if (err.data.image_status != 'normal') { uni.$u.toast('识别失败,请重新上传正确的证件照!') throw new Error('image error') } break; case 'card2': if (err.data.image_status != 'normal') { uni.$u.toast('识别失败,请重新上传正确的证件照!') throw new Error('image error') } break; default: uni.$u.toast('上传成功'); } } /** * 百度云识别证件函数 * @params { @type Number | 本地上传图片的途径 { 0-拍照, 1-相册 } @apiName String | 识别证件类型 { 'license'-营业执照, 'card'-身份证正面, 'card2'-身份证反面 } @token | access_token } */ export const BAIDU_OCR = (type, apiName, token) => { return new Promise((resolve, reject) => { let pic = uni.chooseImage({ sizeType: ['compressed'], count: 1, sourceType: type == 0 ? 'camera' : 'album', success(res) { uni.getFileSystemManager().readFile({ filePath: res.tempFilePaths[0], encoding: 'base64', success(file) { uni.showLoading({title: '识别中'}) let baidu_data; // 定义请求的数据 if (apiName == 'license') { BAIDU_REQUEST_API = BAIDU_LICENSE_API baidu_data = BAIDU_BUSSINESS_PARAMS } else { BAIDU_REQUEST_API = BAIDU_IDCARD_API baidu_data = BAIDU_IDCARD_PARAMS if (apiName == 'card') { baidu_data.id_card_side = 'front' } else { baidu_data.id_card_side = 'back' } } baidu_data.image = file.data uni.request({ url: `${BAIDU_REQUEST_API}?access_token=${token}`, method: 'POST', header: { 'content-type': 'application/x-www-form-urlencoded' }, data: baidu_data, success(baidu_res) { uni.hideLoading() ErrExcept(apiName, baidu_res) resolve(res.tempFilePaths[0]) }, fail(baidu_res_reject) { uni.hideLoading() uni.$u.toast('识别失败,请重新上传') reject(baidu_res_reject) } }) }, fail(baidu_reject) { uni.$u.toast('读取失败,请重新上传') reject(baidu_reject) } }) }, fail: (err) => { uni.$u.toast('获取照片失败,请重新上传') reject(err) } }) }) }
使用的组件是 uview2.0
,需要的就替换成自己的组件。《传送地址》
<template> <!-- 营业执照 --> <view class="box_radius" style="margin-top: 20rpx;"> <text>请点击上传您的营业执照</text> <view @click="bindActions('license')"> <image style="width: 100%;margin-top: 20rpx;" :src="fileinp_yin_path || 'http://nq34.gzfloat.com/public/user/license@2x.png'" mode="widthFix"></image> </view> </view> <!-- 身份证正反面 --> <view class="box_radius" style="margin: 20rpx 0;"> <text>请点击上传您的身份证正反面</text> <view> <view @click="bindActions('card')"> <image style="width: 100%;margin: 20rpx 0;" :src="fileinp_zheng_path || 'http://nq34.gzfloat.com/public/user/card@2x.png'" mode="widthFix"></image> </view> <view @click="bindActions('card2')"> <image style="width: 100%;" :src="fileinp_fan_path || 'http://nq34.gzfloat.com/public/user/card2@2x.png'" mode="widthFix"></image> </view> </view> </view> <!-- Action Sheet组件 --> <u-action-sheet @select="selectActions" @close="actionShow = false" :actions="actionList" :safeAreaInsetBottom="true" cancelText="取消" :closeOnClickOverlay="true" :closeOnClickAction="true" :title="actionTitle" :show="actionShow"></u-action-sheet> </template> <script> import { GET_ACCESS_TOKEN, BAIDU_OCR } from '@/utils/ocr/index.js' export default { data() { return { name: '', actionShow: false, actionTitle: '上传营业执照', actionList: [{id: 0, name: '拍照'},{id: 1, name: '相册'}], name: '', actionTitle: '', fileinp_yin_path: '', fileinp_zheng_path: '', fileinp_fan_path: '' } }, methods: { bindActions(name) { this.actionShow = true if (name == 'license') { this.name = 'license' this.actionTitle = '上传营业执照' } else if (name == 'card') { this.name = 'card' this.actionTitle = '上传身份证正面' } else { this.name = 'card2' this.actionTitle = '上传身份证反面' } }, async selectActions(index) { // 获取鉴权 token const BAIDU_ACCESS_TOKEN = await GET_ACCESS_TOKEN() // 选择图片以及鉴别图片 const chooseResult = await BAIDU_OCR(index.id, this.name, BAIDU_ACCESS_TOKEN) // 上传图片 const result = await this.uploadFilePromise(chooseResult) if (this.name == 'license') { this.fileinp_yin_path = result } else if (this.name == 'card') { this.fileinp_zheng_path = result } else { this.fileinp_fan_path = result } } } } </script>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。