進(jìn)軍微信第一步:接入微信JS-SDK

【前言】 某天,接到這么一個(gè)需求:自定義微信網(wǎng)頁(yè)分享出來(lái)的標(biāo)題,描述和圖標(biāo)。以前沒(méi)玩過(guò)這個(gè),感覺(jué)應(yīng)該很簡(jiǎn)單,動(dòng)手了之后,躺過(guò)各種坑才知道并沒(méi)那么容易。完全獨(dú)立研究排錯(cuò),感受頗多,分享出來(lái)給大家鋪一鋪路

一: 需求來(lái)源

?開(kāi)發(fā)了一個(gè)移動(dòng)端H5活動(dòng)頁(yè)面,該頁(yè)面要實(shí)現(xiàn)微信中的“分享給好友”,“分享到朋友圈”,“分享到QQ”,“分享到騰訊微博”等功能。如果沒(méi)有接入jssdk,分享出來(lái)的就是如下樣子:


微信分享默認(rèn)卡片

?除了標(biāo)題比較容易自定義以外,描述內(nèi)容和圖標(biāo)都是默認(rèn)樣式,好丑。如果就這么分享出去,活動(dòng)本身的吸引力就會(huì)被大打折扣,所以,這個(gè)功能必須完成!
?

二: 需要工具

?我自己在開(kāi)發(fā)的時(shí)候,不知道需要這些東西,都是遇到一個(gè)坑,才去找的一個(gè)蘿卜;這里提前提到,帶你走捷徑:

  1. 微信公眾平臺(tái)技術(shù)文檔 - 必備,接入微信的功能,一切都是從這里開(kāi)始
  2. 微信JS接口簽名校驗(yàn)工具 - 該工具能幫你核查生成的簽名的正確性
  3. 微信web開(kāi)發(fā)者工具 - 模擬web網(wǎng)頁(yè)調(diào)試微信接口,能查看JS-SDK的狀態(tài),查看權(quán)限列表,還能接入移動(dòng)設(shè)備調(diào)試;完美解決微信接口調(diào)試難的問(wèn)題。獲取方法: 登錄微信公眾平臺(tái) -> 進(jìn)入開(kāi)發(fā)者工具 -> 下載微信web開(kāi)發(fā)者工具 下載后,使用方法和chrome類(lèi)似,不多說(shuō)。
  4. Xshell - 用來(lái)部署服務(wù)端代碼(linux環(huán)境),因?yàn)榻尤胛⑿拍K必須是線上聯(lián)調(diào)的,所以你的服務(wù)端都是需要部署到線上,即使是聯(lián)調(diào)服務(wù)器,也要滿(mǎn)足外網(wǎng)能訪問(wèn)。當(dāng)然,如果服務(wù)端人員能幫你解決這個(gè)問(wèn)題,請(qǐng)無(wú)視。
    ?

三: 開(kāi)發(fā)前需要

1. 綁定域名

?登錄微信公眾平臺(tái)(真實(shí)運(yùn)營(yíng)的服務(wù)號(hào)),進(jìn)入“公眾號(hào)設(shè)置”,選擇導(dǎo)航標(biāo)簽中的“功能設(shè)置”,填寫(xiě)“JS接口安全域名”。注意,該頁(yè)上也有描述,需要下載一個(gè) .txt 文件放到你網(wǎng)頁(yè)(你所填寫(xiě)的安全域名)要部署的服務(wù)器的根目錄(或目錄路徑)下,這個(gè)文件是微信用來(lái)檢測(cè)你的服務(wù)器是否可達(dá)使用,不同公眾號(hào)的txt文件不同,我就不小心用放在桌面上的自己的公眾號(hào)的測(cè)試文件放到服務(wù)器中,然后以公司的服務(wù)號(hào)去跑,一直通不過(guò)。
?服務(wù)號(hào)才有對(duì)應(yīng)的接口權(quán)限,如果你綁定了一個(gè)私人的公眾號(hào),一樣沒(méi)法使用。你可以“開(kāi)發(fā)者中心”查看一下你是否擁有對(duì)應(yīng)接口的開(kāi)發(fā)權(quán)限,免得白忙活。

2. 引入 JS 文件

? 和其他的模塊一致,想要調(diào)用微信的功能,同樣也需要引入微信js文件,目前最新版本為1.2.0;該文件有 http形式https形式,下載之后在需要調(diào)用js接口的頁(yè)面引入。也可以全局引入,已經(jīng)壓縮過(guò),大小為11.5k,還算小。
?模塊化推薦使用 AMD/CMD 標(biāo)準(zhǔn)加載
?

四: 開(kāi)始開(kāi)發(fā)

1. 權(quán)限驗(yàn)證配置

?有了上述的準(zhǔn)備,我們可以通過(guò)config在要使用JS-SDK的頁(yè)面注入配置信息,這是你調(diào)用微信接口微信驗(yàn)證的入口。config接收一個(gè)對(duì)象,具體如下:

接口權(quán)限配置

即:

wx.config({
  debug: false,    // 是否打開(kāi)調(diào)試模式,調(diào)用的api會(huì)被alert出來(lái),在pc端也能看到log信息
  appid:'',   // 必填,微信公眾號(hào)的唯一標(biāo)識(shí)
  timestamp: ,  // 必填,生成簽名的時(shí)間戳
  nonceStr: '',  // 必填,生成簽名的隨機(jī)串
  signature: '',  //必填,用于驗(yàn)證的簽名
  jsApiList: []    //必填,需要使用到的JS接口列表
})

?大部分文檔都這么一說(shuō)而過(guò),然而還是容易踩坑。
?糞坑: 為什么叫糞坑,因?yàn)樽銐虻椭巧獭R婚_(kāi)始沒(méi)對(duì)微信公眾號(hào)的這些機(jī)制了解多少,直接用appid, appSecret生成靜態(tài)的accesstoken,然后用accesstoken生成了靜態(tài)的jsapi_ticket,最后生成靜態(tài)的signature,然后就把這幾個(gè)參數(shù)填進(jìn)去了,肯定錯(cuò)啊。這些信息除了idsecret其他都是動(dòng)態(tài)的。
?坑1: 可以從上圖中看出來(lái),我直接設(shè)置debug參數(shù)為false,并不是我覺(jué)得多余,而是根本看不明白,本地調(diào)試基本沒(méi)法看出問(wèn)題。怎么辦? 在 “需要工具” 中提供的微信web開(kāi)發(fā)者工具,他由微信團(tuán)隊(duì)提供,用了才知道,要啥debug調(diào)試,這個(gè)工具簡(jiǎn)直完美,所有信息展示 清清楚楚,一目了然。
?坑2: timestamp配置項(xiàng)處沒(méi)有引號(hào),也就是說(shuō),這里的類(lèi)型是 INT。另外,還有一個(gè)很重要的就是,這里 單位是秒,相信絕大多數(shù)一開(kāi)始和我一樣,以為是毫秒,直接new Date().getTime()完事。踩了踩了。
?坑3:nonceStr必須遵循駝峰式命名規(guī)則。這里比較容易混淆是因?yàn)樵谏珊灻且徊剑枰冉M成字符串string1,那里要求所有key包括noncestr也都是小寫(xiě)的,所以誤以為這里也是小寫(xiě)的。
?坑4:或許你有看到jsApiList中有的文檔有checkJsApi項(xiàng),有的又沒(méi)有。是這樣的:在真正調(diào)用微信接口功能如“分享到朋友圈”之前,我們可以對(duì)微信接口先進(jìn)行驗(yàn)證接口是否可用,即,checkJsApi是一個(gè)基礎(chǔ)接口,所以也要加入該數(shù)組中,如下

ready中的checkJsApi接口

?為了不打亂思路,這里將如何獲取簽名過(guò)程放在最后面因涉及太多重要信息,這個(gè)步驟要求必須在服務(wù)端實(shí)現(xiàn)。

2. ready驗(yàn)證成功回調(diào)

?config信息驗(yàn)證成功后,下一步就是使用微信的各種接口。微信提供config的回調(diào)函數(shù)ready(),供我們執(zhí)行這些接口。注意:config是一個(gè)客戶(hù)端的異步操作,所以如果需要在頁(yè)面加載時(shí)就調(diào)用相關(guān)接口,則須把相關(guān)接口放在ready函數(shù)中調(diào)用來(lái)確保正確執(zhí)行。但是如果是一些交互操作,這不必寫(xiě)在ready中,可以直接調(diào)用。比如說(shuō)“發(fā)送給好友”就是與用戶(hù)交互后的操作。

3. error驗(yàn)證失敗處理
wx.error(function(res){
  console.log(res);      // res為微信返回的錯(cuò)誤結(jié)果
})
4. 自定義分享內(nèi)容

共用信息定義

?這里我定義了我們需要分享的一些內(nèi)容,如, 標(biāo)題,內(nèi)容描述,和圖片地址。
坑:這里的圖片地址必須是絕對(duì)地址。上圖中的data.url是發(fā)送給微信校驗(yàn)的那個(gè)url.

4. 定義分享接口

?這里只寫(xiě)了幾個(gè)最常用的接口,如需要分享西,

  • 分享到朋友圈 - onMenuShareTimeLine()

接受一個(gè)對(duì)象,分享到朋友圈需要自定義三個(gè)內(nèi)容,展示圖標(biāo)imgUrl,標(biāo)題title和鏈接地址link

wx.onMenuShareTimeline({
    title: '', // 分享標(biāo)題
    link: '', // 分享鏈接,該鏈接域名或路徑必須與當(dāng)前頁(yè)面對(duì)應(yīng)的公眾號(hào)JS安全域名一致
    imgUrl: '', // 分享圖標(biāo)絕對(duì)路徑
    success: function () { 
        // 用戶(hù)確認(rèn)分享后執(zhí)行的回調(diào)函數(shù)
    },
    cancel: function () { 
        // 用戶(hù)取消分享后執(zhí)行的回調(diào)函數(shù)
    }
});
  • 發(fā)送給好友 - onMenuShareAppMessage()

?“發(fā)送給好友”需要自定義四個(gè)信息,標(biāo)題title,描述desc,圖標(biāo)絕對(duì)地址imgUrl和跳轉(zhuǎn)的link

  • 分享到QQ - onMenuShareQQ()

?自定義四個(gè)信息:標(biāo)題title,描述desc,跳轉(zhuǎn)鏈接link,和圖標(biāo)絕對(duì)地址Url

  • 分享到QQ空間 - onMenuShareQZone()
wx.onMenuShareQZone({
    title: title,
    desc: desc, 
    link: link, 
    imgUrl: imgUrl,
    success: function () { 
       // 用戶(hù)確認(rèn)分享后執(zhí)行的回調(diào)函數(shù)
    },
    cancel: function () { 
        // 用戶(hù)取消分享后執(zhí)行的回調(diào)函數(shù)
    }
});

?

JS-SDK使用權(quán)限簽名算法

?很高大上的名字,聽(tīng)著怪嚇人。其實(shí)只要幾個(gè)參數(shù)給對(duì)了,還是很容易處理的。需要注意的是,這個(gè)步驟需要在服務(wù)端實(shí)現(xiàn)
?上面“糞坑”提到的,雖然校驗(yàn)是失敗的,但步驟就是如此了。這里再概括一下:

登錄微信公眾號(hào) →
拿到appId和appSecret →
用他們?nèi)ノ⑿奴@取access_token →
用access_token去獲取jsapi_ticket →
生成一個(gè)隨機(jī)字符串noncestr →
生成當(dāng)前時(shí)間戳,單位是秒 →
用隨機(jī)jsapi_ticket,當(dāng)前時(shí)間戳,隨機(jī)字符串以及分享的url用&拼接成string1 →
對(duì)string1進(jìn)行sha1加密 →
加密后的字符串就是signature →
數(shù)據(jù)返回客戶(hù)端

?先在腦海形成一個(gè)思路。我們?cè)趤?lái)細(xì)看每一步:

1. 獲取access_token

?微信提供access_token的有效期是兩個(gè)小時(shí),即7200秒,超時(shí)失效;且下一次獲取也會(huì)使上次獲取的結(jié)果失效。所以我們需要對(duì)它進(jìn)行動(dòng)態(tài)獲取。目前微信支持每個(gè)公眾號(hào)每天最多2000次的access_token獲取請(qǐng)求。我設(shè)定7000秒去更新一次,這里用的nodejs實(shí)現(xiàn),其實(shí)思路都是一樣的。具體實(shí)現(xiàn)如下:

獲取微信access_token的NodeJs實(shí)現(xiàn)

?這里先校驗(yàn)了本地文件accesss_token.json中的access_token字段是否為空,為空表示是第一次獲取。再利用下面語(yǔ)句判斷本地的是否已經(jīng)過(guò)了我們所設(shè)定的有效期:

accessTokenJson.expire_time < currentTime

如果滿(mǎn)足條件,就重新發(fā)起requestGet請(qǐng)求重新獲取,否則從本地拿。
?為什么要這么做? 因?yàn)閷?duì)外的活動(dòng),如果用戶(hù)量比較大,每一個(gè)用戶(hù)都去獲取一次,微信限定的訪問(wèn)次數(shù)在2000個(gè)訪問(wèn)中就用完了,接下來(lái)當(dāng)天的訪問(wèn)將再也通不過(guò)簽名驗(yàn)證。

2. 生成 jsapi_ticket

?生成jsapi_ticket的步驟和獲取access_token的思路一致,具體如下所示:

利用access_token生成jsapi_ticket

?這里需要注意的是,不僅要判斷ticket是否為空,還要判斷token是否失效。因?yàn)楫?dāng)token提前失效后ticket將變得無(wú)意義.
?另外還要考慮這種情況,某次請(qǐng)求獲取到一個(gè)token后,我們并不能保證其他人員不會(huì)去微信公眾號(hào)或者web url等方式去請(qǐng)求獲取token,這將導(dǎo)致因token被更新而上次的token失效,但我們的程序并不知道,繼續(xù)使用“上一次請(qǐng)求”的token,在下一個(gè)“重新請(qǐng)求”前將一直是失效的,不要漏了這種情況。

3. 生成隨機(jī)字符串

?傳給randomString一個(gè)長(zhǎng)度參數(shù),生成所需要的隨機(jī)長(zhǎng)度字符串。我這里設(shè)定的是長(zhǎng)度為16,代碼如下,簡(jiǎn)單不解釋。

生成指定長(zhǎng)度的隨機(jī)字符串

4. 獲取JS-SDK簽名

?公式:signature=sha1(string1);即,需要生成string1,再對(duì)string1進(jìn)行sha1加密得到signature
?微信文檔中提到,

參與簽名的字段包括noncestr(隨機(jī)字符串), 有效的jsapi_ticket, timestamp(時(shí)間戳), url(當(dāng)前網(wǎng)頁(yè)的URL,不包含#及其后面部分) 。對(duì)所有待簽名參數(shù)按照字段名的ASCII 碼從小到大排序(字典序)后,使用URL鍵值對(duì)的格式(即key1=value1&key2=value2…)拼接成字符串string1.這里需要注意的是所有參數(shù)名均為小寫(xiě)字符。對(duì)string1作sha1加密,字段名和字段值都采用原始值,不進(jìn)行URL 轉(zhuǎn)義。

?其實(shí)簡(jiǎn)單了來(lái)說(shuō),string1就是jsapi_ticket=它的值&noncestr=隨機(jī)字符串&timestamp=當(dāng)前時(shí)間戳(單位秒)&url=當(dāng)前網(wǎng)頁(yè)url。微信文檔說(shuō)要按字段名的字典序排序,請(qǐng)注意,是按字段名的字典序,因?yàn)樽侄蚊蛔儯哉f(shuō)其實(shí)這個(gè)串中的各個(gè)參數(shù)順序是不變的。

獲取 js-sdk 簽名

【填坑】:

  1. 簽名用的noncestrtimestamp必須與wx.config中的nonceStrtimestamp相同。
  2. 簽名用的url必須是調(diào)用JS接口頁(yè)面的完整URL(請(qǐng)用location.href.split('#')[0])確認(rèn),包括'http(s)://'部分,以及'?'后面的GET參數(shù)部分,但不包括'#'hash后面的部分)

?能躺的坑基本已經(jīng)說(shuō)明,如有錯(cuò)誤或缺漏的地方,歡迎交流。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,763評(píng)論 6 539
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,238評(píng)論 3 428
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 177,823評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,604評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,339評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,713評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,712評(píng)論 3 445
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,893評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,448評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,201評(píng)論 3 357
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,397評(píng)論 1 372
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,944評(píng)論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,631評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 35,033評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,321評(píng)論 1 293
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,128評(píng)論 3 398
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,347評(píng)論 2 377

推薦閱讀更多精彩內(nèi)容