في الآونة الأخيرة، كانت وظيفة المغلف الأحمر لكلمة مرور WeChat على وشك الاستخدام. فجأة، أصبح الرئيس قلقًا، وقال إن حفلة الصوف منتشرة جدًا الآن، فهل سيتم استخدام المظروف الأحمر الترويجي البالغ عدده 100000 أيام؟.... إذن هل يمكننا إجراء وظيفة للتحقق مما إذا كان نفس الشخص يتلقى المظروف الأحمر؟ أليس هذا كافيًا؟ ربت على رأسه وتابع: "توم، من فضلك قم بالتعرف على بصمة الصوت!"
العملية المحددة هي كما يلي:
المستخدمون المسجلون في بصمة الصوت (العرض النهائي)
تسجيل الدخول بالبصمة الصوتية (العرض النهائي)
تحميل تعريف الملف:
موضوع PM2
نظرًا لأن موفر خدمة التعرف على بصمة الصوت لا يمكنه استخدام العميل مباشرةً للاتصال المباشر ولأن الصوت غير مدعوم، فمن الضروري تطوير خادم خاص به للاتصال.
مكدس التكنولوجيا koa + co-wecaht-api + mysql + ffmpeg +pm2 + knex
ملاحظة: نظرًا لأن مزود الخدمة لا يدعم ملفات WeChat amr، فأنت بحاجة إلى استخدام ffmpeg لتحويل ملفات WeChat الصوتية amr إلى wav.
فيما يلي بعض التعليمات البرمجية ذات الصلة، مفتوحة. .
تطوير WeChat jssdk إذا كنت معتادًا على WeChat API، فانتقل إلى القسم التالي
احصل على رمز WeChat
var api = await new WechatAPI (
config . appid ,
config . appsecret ,
async ( ) => {
// 传入一个获取全局token的方法
var txt = await fs . readFile ( "./token/access_token.txt" , "utf8" ) ;
return JSON . parse ( txt ) ;
} ,
async token => {
// 请将token存储到全局,跨进程、跨机器级别的全局,比如写到数据库、redis等
// 这样才能在cluster模式及多机情况下使用,以下为写入到文件的示例
await fs . writeFile ( "./token/access_token.txt" , JSON . stringify ( token ) ) ;
}
) ;
ملاحظة: إذا تعذرت قراءة ملف الرمز المميز، فقم بإنشاء ملف نصي جديد يدويًا في الدليل المقابل، مثل access_token.txt
احصل على توقيع WeChat
var jsapi_ticket = await api . getLatestTicket ( ) ;
let nonce_str = 'abcdefg' ; // 密钥,字符串任意,可以随机生成
let timestamp = parseInt ( new Date ( ) . getTime ( ) / 1000 ) + '' ; // 时间戳
let url = ctx . request . body . url ; // 使用接口的url链接,不包含#后的内容
let str = 'jsapi_ticket=' + jsapi_ticket . ticket + '&noncestr=' + nonce_str + '×tamp=' + timestamp + '&url=' + url ;
let signature = sha1 ( str ) ;
ctx . body = {
appId : config . appid ,
timestamp : timestamp ,
nonceStr : nonce_str ,
signature : signature
}
طلب عبر المجال
const Koa = require ( "koa" ) ;
const app = new Koa ( ) ;
const cors = require ( "koa-cors" ) ;
... . .
app . use (
cors ( {
origin : "http://www.xxxx.com" ,
maxAge : 5 ,
credentials : true ,
allowMethods : [ "OPTIONS" , "GET" , "POST" , "DELETE" ] ,
allowHeaders : [ 'Content-Type' , 'Accept' ]
} )
) ;
تحويل الترميز ffmpeg
const ffmpeg = require ( 'fluent-ffmpeg' ) ;
... .
var command = ffmpeg ( _delPath . amr )
. audioBitrate ( '16k' ) //16k音频采样率
. audioFrequency ( 16000 ) //16比特音频信号
. audioQuality ( 10 ) //音频质量
. on ( 'end' , function ( ) {
console . log ( 'file has been converted succesfully' ) ;
resolve ( ) ;
} )
. on ( 'error' , function ( err ) {
reject ( err . message )
console . log ( 'an error happened: ' + err . message ) ;
} )
. save ( _delPath . fix ) ;
إرسال خادم البصمة الصوتية
const rp = require ( "request-promise" ) ;
... . .
var vprData = {
method : "POST" ,
url : "http://www.xxxx.com" ,
headers : {
"cache-control" : "no-cache" ,
"x-udid" : "xxxxxx" ,
"x-session-key" : "xxxx" ,
"x-task-config" : "xxxxxx" ,
"x-request-date" : "xxxxxx" ,
"x-sdk-version" : "5.1" ,
"x-app-key" : "xxxxxxx"
} ,
formData : {
// Like <input type="file" name="file">
file : {
value : fs . createReadStream ( soundData . path ) ,
options : {
filename : soundData . name ,
contentType : soundData . type //mp3 = audio/mpeg, wav = audio/wav
}
}
}
} ;
var xml = await rp ( vprData ) ;
//xml to json
var resJson = { } ;
var parseString = require ( 'xml2js' ) . parseString ;
await new Promise ( ( resolve , reject ) => {
parseString ( xml . toString ( ) , async ( err , result ) => {
resJson = result . ResponseInfo ;
//do something
resolve ( ) ;
} ) ;
} ) ;
تكنولوجيا المكدس vue + vue-router + axios.
قم بإزالة الزر المنسوخ المنبثق الذي تم الضغط عليه لفترة طويلة على WeChat
mounted ( ) {
document . oncontextmenu = function ( e ) {
e . preventDefault ( ) ;
} ;
//初始化 微信jssdk
vm . wx_init ( ) ;
}
احصل على توقيع WeChat وقم بتسجيل الحدث
wx . config ( {
debug : false , // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId : res . appId , // 必填,公众号的唯一标识
timestamp : res . timestamp , // 必填,生成签名的时间戳
nonceStr : res . nonceStr , // 必填,生成签名的随机串
signature : res . signature , // 必填,签名,见附录1
jsApiList : [
"onMenuShareTimeline" ,
"onMenuShareAppMessage" ,
"uploadVoice" ,
"startRecord" ,
"playVoice" ,
"stopRecord" ,
"onVoicePlayEnd"
] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
} ) ;
اطلب من المستخدم مسبقًا ترخيص وظيفة التسجيل لتجنب المطالبة بالترخيص في نفس الوقت عند بدء التسجيل رسميًا، في هذا الوقت، تكون حالة وظيفة التسجيل خارج نطاق السيطرة.
if ( ! localStorage . rainAllowRecord || localStorage . rainAllowRecord !== "true" ) {
wx . startRecord ( {
success : function ( ) {
localStorage . rainAllowRecord = "true" ;
wx . stopRecord ( ) ;
} ,
cancel : function ( ) {
alert ( "用户拒绝授权录音" ) ;
}
} ) ;
}
حسنًا، الحديث رخيص، أظهر لك الرمز.
كيفية الاستخدام
git clone https: //github.com/ssttm169/tom-vpr.git
cd server
npm i / yarn
npm run dev //本地开发
npm start //服务器跑
//或者
cd client
npm i / yarn
npm run dev //本地开发
npm start //服务上跑客户端