基于nodejs的微信JS-SDK簡(jiǎn)單應(yīng)用實(shí)現(xiàn)
2015 是 Hybrid App 崛起之年 ,Web App 和 Native App 各有其強(qiáng)大之處,也有著致命的缺點(diǎn),人們一邊追求native流暢的用戶(hù)體驗(yàn),一邊同時(shí)期望產(chǎn)品能夠快速的迭代更新,Hybrid 成為必然的趨勢(shì)。
鵝廠(chǎng)一馬當(dāng)先,發(fā)布了業(yè)內(nèi)震驚一時(shí)的 JS-SDK , 這對(duì)于基于微信的h5開(kāi)發(fā)者來(lái)說(shuō)簡(jiǎn)直是如降甘露,從此開(kāi)發(fā)者們告別了用箭頭來(lái)提示右上角可以分享,并且隨時(shí)可以使用微信的原生能力,微信變成了一個(gè)超級(jí)瀏覽器。
一、準(zhǔn)備工作
1.在微信公眾平臺(tái)申請(qǐng)測(cè)試賬號(hào),并設(shè)置好好 JS 接口安全域名 (注:域名必須可以外網(wǎng)訪(fǎng)問(wèn))
2.查看微信開(kāi)發(fā)者文檔
二、開(kāi)始編碼
使用微信 sdk 必須自己實(shí)現(xiàn)微信的簽名算法。
大概需要4個(gè)步驟:
1.獲取access_token;
2.根據(jù)access_token 獲取jsapi_ticket
3. 根據(jù) appId(公眾號(hào)唯一id)、noncestr(隨機(jī)字符串)、timestamp(時(shí)間戳)、url(當(dāng)前頁(yè)面完整url,不包括#aaa=bbb) 通過(guò)sha1算法簽名
4.將信息返回給前端 , 設(shè)置wx.config。
由于獲取access_token 和jsapi_ticket 的接口都有訪(fǎng)問(wèn)限制,所以明確指出需要第三方做緩存處理。此處我們緩存jsapi_ticket 就可以了。
/config/wechat.cfg.js
module.exports = { grant_type: 'client_credential', appid: 'xxxxxxxxxxxxxxx', secret: 'xxxxxxxxxxxxxxxxxxxxxxxxxx', noncestr:'Wm3WZYTPz0wzccnW', accessTokenUrl:'https://api.weixin.qq.com/cgi-bin/token', ticketUrl:'https://api.weixin.qq.com/cgi-bin/ticket/getticket', cache_duration:1000*60*60*24 //緩存時(shí)長(zhǎng)為24小時(shí) }
最主要部分是簽名:
signature.js
var request = require('request'), cache = require('memory-cache'), sha1 = require('sha1'), config = require('../config/wechat.cfg'); exports.sign = function (url,callback) { var noncestr = config.noncestr, timestamp = Math.floor(Date.now()/1000), //精確到秒 jsapi_ticket; if(cache.get('ticket')){ jsapi_ticket = cache.get('ticket'); console.log('1' + 'jsapi_ticket=' + jsapi_ticket + '&noncestr=' + noncestr + '×tamp=' + timestamp + '&url=' + url); callback({ noncestr:noncestr, timestamp:timestamp, url:url, jsapi_ticket:jsapi_ticket, signature:sha1('jsapi_ticket=' + jsapi_ticket + '&noncestr=' + noncestr + '×tamp=' + timestamp + '&url=' + url) }); }else{ request(config.accessTokenUrl + '?grant_type=' + config.grant_type + '&appid=' + config.appid + '&secret=' + config.secret ,function(error, response, body){ if (!error && response.statusCode == 200) { var tokenMap = JSON.parse(body); request(config.ticketUrl + '?access_token=' + tokenMap.access_token + '&type=jsapi', function(error, resp, json){ if (!error && response.statusCode == 200) { var ticketMap = JSON.parse(json); cache.put('ticket',ticketMap.ticket,config.cache_duration); //加入緩存 console.log('jsapi_ticket=' + ticketMap.ticket + '&noncestr=' + noncestr + '×tamp=' + timestamp + '&url=' + url); callback({ noncestr:noncestr, timestamp:timestamp, url:url, jsapi_ticket:ticketMap.ticket, signature:sha1('jsapi_ticket=' + ticketMap.ticket + '&noncestr=' + noncestr + '×tamp=' + timestamp + '&url=' + url) }); } }) } }) } }
由于只是簡(jiǎn)單的demo , 也就沒(méi)有采用promise,而是采用的普通的回調(diào)。
客戶(hù)端部分
document.getElementById('refresh').onclick = function(){location.reload();} /** * 以下內(nèi)容多摘自官方demo * **/ wx.config({ debug: true, // 開(kāi)啟調(diào)試模式,調(diào)用的所有api的返回值會(huì)在客戶(hù)端alert出來(lái),若要查看傳入的參數(shù),可以在pc端打開(kāi),參數(shù)信息會(huì)通過(guò)log打出,僅在pc端時(shí)才會(huì)打印。 appId: appId, // 必填,公眾號(hào)的唯一標(biāo)識(shí) timestamp: timestamp, // 必填,生成簽名的時(shí)間戳 nonceStr: nonceStr, // 必填,生成簽名的隨機(jī)串 signature: signature,// 必填,簽名,見(jiàn)附錄1 jsApiList: ['checkJsApi', 'onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ', 'onMenuShareWeibo', 'hideMenuItems', 'showMenuItems', 'hideAllNonBaseMenuItem', 'showAllNonBaseMenuItem', 'translateVoice', 'startRecord', 'stopRecord', 'onRecordEnd', 'playVoice', 'pauseVoice', 'stopVoice', 'uploadVoice', 'downloadVoice', 'chooseImage', 'previewImage', 'uploadImage', 'downloadImage', 'getNetworkType', 'openLocation', 'getLocation', 'hideOptionMenu', 'showOptionMenu', 'closeWindow', 'scanQRCode', 'chooseWXPay', 'openProductSpecificView', 'addCard', 'chooseCard', 'openCard'] // 必填,需要使用的JS接口列表, }); wx.ready(function(){ // 1 判斷當(dāng)前版本是否支持指定 JS 接口,支持批量判斷 document.querySelector('#checkJsApi').onclick = function () { wx.checkJsApi({ jsApiList: [ 'getNetworkType', 'previewImage' ], success: function (res) { alert(JSON.stringify(res)); } }); }; // 2. 分享接口 // 2.1 監(jiān)聽(tīng)“分享給朋友”,按鈕點(diǎn)擊、自定義分享內(nèi)容及分享結(jié)果接口 document.querySelector('#onMenuShareAppMessage').onclick = function () { wx.onMenuShareAppMessage({ title: '互聯(lián)網(wǎng)之子', desc: '在長(zhǎng)大的過(guò)程中,我才慢慢發(fā)現(xiàn),我身邊的所有事,別人跟我說(shuō)的所有事,那些所謂本來(lái)如此,注定如此的事,它們其實(shí)沒(méi)有非得如此,事情是可以改變的。更重要的是,有些事既然錯(cuò)了,那就該做出改變。', link: 'http://movie.douban.com/subject/25785114/', imgUrl: 'http://demo.open.weixin.qq.com/jssdk/images/p2166127561.jpg', trigger: function (res) { // 不要嘗試在trigger中使用ajax異步請(qǐng)求修改本次分享的內(nèi)容,因?yàn)榭蛻?hù)端分享操作是一個(gè)同步操作,這時(shí)候使用ajax的回包會(huì)還沒(méi)有返回 alert('用戶(hù)點(diǎn)擊發(fā)送給朋友'); }, success: function (res) { alert('已分享'); }, cancel: function (res) { alert('已取消'); }, fail: function (res) { alert(JSON.stringify(res)); } }); alert('已注冊(cè)獲取“發(fā)送給朋友”狀態(tài)事件'); }; // 5 圖片接口 // 5.1 拍照、本地選圖 var images = { localId: [], serverId: [] }; document.querySelector('#chooseImage').onclick = function () { wx.chooseImage({ success: function (res) { images.localId = res.localIds; alert('已選擇 ' + res.localIds.length + ' 張圖片'); } }); }; // 5.2 圖片預(yù)覽 document.querySelector('#previewImage').onclick = function () { wx.previewImage({ current: 'http://img5.douban.com/view/photo/photo/public/p1353993776.jpg', urls: [ 'http://img3.douban.com/view/photo/photo/public/p2152117150.jpg', 'http://img5.douban.com/view/photo/photo/public/p1353993776.jpg', 'http://img3.douban.com/view/photo/photo/public/p2152134700.jpg' ] }); }; // 7.2 獲取當(dāng)前地理位置 document.querySelector('#getLocation').onclick = function () { wx.getLocation({ success: function (res) { alert(JSON.stringify(res)); }, cancel: function (res) { alert('用戶(hù)拒絕授權(quán)獲取地理位置'); } }); }; // 9 微信原生接口 // 9.1.1 掃描二維碼并返回結(jié)果 document.querySelector('#scanQRCode0').onclick = function () { wx.scanQRCode(); }; }); wx.error(function(res){ JSON.stringify(res) });
至此,基本功能已經(jīng)完成。附上效果圖
踩的坑:
1.簽名算法不一致: 通過(guò) http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign 驗(yàn)證算法正確性
2.url 必須完全一致,并且外網(wǎng)可訪(fǎng)問(wèn)。 將代碼部署到 BAE ,或者其他應(yīng)用引擎服務(wù)器上。
3.timestamp需要精確到秒。
源碼:https://github.com/liaobin312716/wechat-sdk-demo/
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
nodejs socket實(shí)現(xiàn)的服務(wù)端和客戶(hù)端功能示例
這篇文章主要介紹了nodejs socket實(shí)現(xiàn)的服務(wù)端和客戶(hù)端功能,結(jié)合具體實(shí)例形式分析了nodejs基于socket通信實(shí)現(xiàn)的服務(wù)端與客戶(hù)端功能相關(guān)操作技巧,需要的朋友可以參考下2017-06-06vscode安裝教程以及配置node.js環(huán)境全過(guò)程
這篇文章主要給大家介紹了關(guān)于vscode安裝教程以及配置node.js環(huán)境的相關(guān)資料,VSCode是一款由微軟開(kāi)發(fā)的輕量級(jí)編輯器,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-10-10Nodejs實(shí)現(xiàn)短信驗(yàn)證碼功能
使用Nodejs的開(kāi)發(fā)者愈來(lái)越多,基于Nodejs的后臺(tái)開(kāi)發(fā)也多了起來(lái),像短信驗(yàn)證碼、短信群發(fā)、國(guó)際短信這些需求,完全可以采用第三方接口來(lái)實(shí)現(xiàn),云片就提供了這樣的接口2017-02-02vscode調(diào)試node.js的實(shí)現(xiàn)方法
這篇文章主要介紹了vscode調(diào)試node.js的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03nodejs實(shí)現(xiàn)連接mongodb數(shù)據(jù)庫(kù)的方法示例
這篇文章主要介紹了nodejs實(shí)現(xiàn)連接mongodb數(shù)據(jù)庫(kù)的方法,結(jié)合實(shí)例形式分析了nodejs針對(duì)mongodb數(shù)據(jù)庫(kù)的簡(jiǎn)單連接、查詢(xún)及關(guān)閉等操作技巧,需要的朋友可以參考下2018-03-03詳解node.js創(chuàng)建一個(gè)web服務(wù)器(Server)的詳細(xì)步驟
這篇文章主要介紹了詳解node.js創(chuàng)建一個(gè)web服務(wù)器(Server)的詳細(xì)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01理解 Node.js 事件驅(qū)動(dòng)機(jī)制的原理
本篇文章主要介紹了理解 Node.js 事件驅(qū)動(dòng)機(jī)制的原理,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08