微信網頁授權+分享踩過的坑
背景
折磨我兩個工作日加週末一天的問題,我覺得還是有必要記錄一下,為什麼程式設計師總是加班,就是遇到這些意想不到的問題
需求
領導:我想做兩個頁面,放在微信裡面可以訪問
我:簡單啊,用H5實現
產品設計中...
產品:好了,看看沒問題就開始開發吧
我:什麼時候多了一個需要獲取使用者資訊(產品總是給人驚喜不端)
沒有試過微信授權這一塊,首先內心三連問,能不能拒絕,能不能改需求,能不能通過熟悉的祕方實現;然而並沒有什麼用(笑哭表情)
開發中
業務功能沒什麼難點,模擬一個使用者資訊,很快就開發完成了...
微信網頁授權
官方文件: https://mp.weixin.qq.com/wiki...
1.登入自己的服務號,檢視已有的許可權
注意:這裡只能是服務號,訂閱號沒有許可權,服務號只能由企業和組織申請
2.公眾號設定
注意:授權回撥域名配置規範為全域名,比如需要網頁授權的域名為:www.qq.com,配置以後此域名下面的頁面 http://www.qq.com/music.html 、 http://www.qq.com/login.html 都可以進行OAuth2.0鑑權。但 http://pay.qq.com 、 http://music.qq.com 、 http://qq.com無法進行OAuth2.0...
注意:下載這個檔案放在域名對應的根目錄下
3.連結的生成
https://open.weixin.qq.com/co...
以訪問www.qq.com/#/detail.html為例,上面第2步的網頁授權域名設定成 www.qq.com
REDIRECT_URI為encodeURIComponent(' http://www.qq.com/#/detail.html ')
SCOPE為snsapi_base或snsapi_userinfo,區別是隻獲取使用者id,還是獲取更多使用者資訊
state隨便寫吧,以123為例(沒有看出具體有什麼用)
其它引數不變
注意:為什麼要用encodeURIComponent,你想想,你在url裡面直接寫url,怎麼能直接把它解析成引數
4.放在微信裡訪問
把第3步上面生成的連結,做為聊天訊息,拷貝到微信裡面,點選開啟,此時我們用alert(location.href)就會發現,地址變成了 http://www.qq.com/?code=生成...
// 獲取url引數 export function getQueryVariable(variable) { const query = window.location.search.substring(1) const vars = query.split("&") for (let i=0; i<vars.length; i++) { const pair = vars[i].split("=") if(pair[0] === variable) return pair[1] } return undefined } // 獲取code的值 const code = getQueryVariable('code')
注意:code只能用一次,而且還有時間限制,code插入的位置尤其要注意,不是在
/#/ 後面,所以用vue或react的路由元件中獲取路由引數方式是不可行的,老老實實的寫原生js獲取
5.通過code獲取使用者id
code獲取到了以後前端就無能為力了,接下來的步驟只能交給後臺了(資料安全性考慮,比如AppSecret不能暴露給前端),自古以來,前端的地位略低於後端,nodejs的出現極大的拯救了前端,雖然後面的事情前端做不了,但我們可以用nodejs或者是類似於postman這種的工具,把後面的介面模擬跑通,然後直接告訴後端,你該調什麼介面,用什麼引數,後端文件都不用看;當然你也可以做個小白紙,什麼都拋給後端,讓後端指揮你怎麼做(在一個團隊中,各個角色的重要性,就看 能做的 事情)
網頁授權就這麼搞完了,是不是很簡單(笑哭表情),可以愉快的玩耍了
當我把這個連結通過微信右上角分享給同事一起測試時,啪啪打臉了...,呈現的現象
1.通過code獲取使用者id,報錯了
2.分享標題,描述,圖示好醜,我能不能改(好像沒有分享這個需求,但不分享的話,使用者怎麼看,我要不要做,沒有這個需求,我要不要把鍋丟給產品,我好方,但僅有的一點點職業素養告訴我,我還是做吧,做為一個合格的程式設計師,必備的技能不就是腦補一些產品沒想到需求嗎(笑哭表情))
分析原因:
1.打印出分享的地址alert(location.href),為 http://www.qq.com/?code=上一... ,微信分享出去的是當前訪問的地址(原滋原味,加了一些防腐劑,多了一個from=xxxx,應該是來源),但我理想中想要的是上面第3中的地址(重定向之前的地址),報錯的原因是同一個code用了兩次
解決思路:
1.自定義分享地址,此時的思路是,地址改成 https://open.weixin.qq.com/co... 這種
2.自定義標題,描述和圖片
3.最終方案看下面
微信網頁分享
官方文件: https://mp.weixin.qq.com/wiki...
1.還是先配置相應的許可權
2.生成簽名(後端做的,前端可以選擇跳過)
這個時候就不得不吐槽微信的文件了,殘缺了,在第一步就卡住了,只能求助網友,後面我發現
這裡有,IP白名單也要設定,否則是拿不到access_token的,其它的簽名怎麼生成的後端照著文件做就行了
注意點:網頁授權和分享是兩個完全獨立的模組,分享的access_token和授權返回的access_token是完全不一樣的概念
3.前端配置
yarn add weixin-js-sdk
此時我的版本是"weixin-js-sdk": "^1.4.0-test", 微信客戶端的版本是7.0.4,竟然遇到一個大坑
微信官方讓我用最新的介面,我試了很久都沒有調通,總以為是自己的姿勢不對,後面實在不行了,我試了一下老介面,竟然通了,竟然通了,竟然通了,我想崩潰了
上程式碼
wx.config({ debug: false, // 開啟除錯模式,呼叫的所有api的返回值會在客戶端alert出來,在pc端時會打印出來,不需要的話可以將true改成false。 appId: data.appid,// 必填,公眾號的唯一標識 timestamp: data.timestamp,// 必填,生成簽名的時間戳 nonceStr: data.nonceStr,// 必填,生成簽名的隨機串 signature: data.signature,// 必填,簽名 jsApiList: ['onMenuShareAppMessage','onMenuShareTimeline','onMenuShareQQ','onMenuShareQZone'] }) wx.ready(function () { //分享到朋友圈 wx.onMenuShareTimeline({ title, // 分享標題 link, // 分享連結,該連結域名或路徑必須與當前頁面對應的公眾號JS安全域名一致 imgUrl, // 分享圖示 }) //分享給朋友 wx.onMenuShareAppMessage({ title, // 分享標題 desc, // 分享描述 link, // 分享連結,該連結域名或路徑必須與當前頁面對應的公眾號JS安全域名一致 imgUrl, // 分享圖示 }) //分享到QQ wx.onMenuShareQQ({ title, // 分享標題 desc, // 分享描述 link, // 分享連結,該連結域名或路徑必須與當前頁面對應的公眾號JS安全域名一致 imgUrl, // 分享圖示 }) //分享到QQ空間 wx.onMenuShareQZone({ title, // 分享標題 desc, // 分享描述 link, // 分享連結,該連結域名或路徑必須與當前頁面對應的公眾號JS安全域名一致 imgUrl, // 分享圖示 }) })
注意:
1.data是後臺返回的簽名信息
2.分享連結,該連結域名必須與當前頁面對應的公眾號JS安全域名一致,公眾號裡面配置的是www.qq.com,這裡分享的地址只能是以www.qq.com開頭的,和我們理想的 https://open.weixin.qq.com/co... 開頭差距很大(怎麼授權,好方)
如果只是單純的自定義分享,到這裡就結束了,如果既要分享又要授權,又有問題需要解決了
4.重定向
- 初始開啟地址為: http://www.qq.com/#/detail.html ,這個時候不帶code
- 進入頁面之後。location.href = ' https://open.weixin.qq.com/co... ' (下面都稱為重定向)
- 頁面地址變成了 http://www.qq.com/?code=生成...
- 用的是同一個頁面,所以需要判斷url有沒有code,來決定是否要執行第2步,否則會死迴圈
文章寫到這裡,已經解決了授權+分享,是不是感覺故事很平穩,一部好的電影怎麼能這麼快結束
高潮(大坑來了)
現象
微信中開啟頁面,用安卓的物理返回鍵,點一下返回不了,需要連續快速點兩下才能退出
分析原因
開啟的頁面是不帶code的地址,經過重定向後,生成了帶code的地址,此時瀏覽器的歷史記錄中會有兩條記錄,從帶code的地址返回到不帶code的地址,頁面判斷沒有帶code,又會重定向到帶code的頁面,產生了死迴圈
解決方案
1.不讓它產生多一條的記錄
首先想到的是location.replace(url), 發現把url替換成授權的地址時( https://open.weixin.qq.com/co... ),並不會像想象中的那樣工作,還是會有兩條歷史記錄(不清楚微信為什麼不解決,還是解決不了)
結果:失敗
2.程式碼控制清除一條歷史記錄
const params = getQueryParams() const code = sessionStorage.getItem('code') if (!params.code && !code) { let url = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${yourAppId}&redirect_uri=${encodeURIComponent(location.href)}&response_type=code&scope=snsapi_base&state=1#wechat_redirect` window.location.replace(url) } else if(!code){ sessionStorage.setItem('code', params.code) history.back() }
搜尋了一大圈,看見了這段程式碼(來自: https://www.cnblogs.com/wonyu... ),彷彿看見了光,裡面比較講究的就是
sessionStorage(只在當前會話有效),用當前會話視窗儲存的code,來判斷不帶code的頁面要不要重定向
看似很完美的程式碼,還是逃不過微信的大坑,通過連結進入時,偶爾會遇到頁面空白
原因:
上面用到的歷史記錄返回,頁面不重新整理(偶爾),我嘗試過強制微信瀏覽器重新整理,甚至懷疑是vue的坑,然後用原生寫了一段js來操作dom,並沒有什麼用
最後發現返回的時候,js都能正常的執行, UI不重新渲染,UI不重新渲染,UI不重新渲染 ,偶爾出現,不是必現,我再次好方
結果:偶爾失敗
3.返回兩次,才能退出
借鑑上面的思路,判斷當前會話視窗儲存的code是否有值,有值就不重定向
結果:解決了偶爾不渲染的問題和死迴圈的問題,但對於有輕微強迫症的我來說,需要點兩次才能返回還是挺難接受的
本來屬於愉快的週末,就在微信這個大坑裡結束了,關上電腦,沉思一會(想想如何說服測試同學這個問題解決不了,是微信的坑(笑哭表情))
結尾
處女座最大的悲哀就是心裡不能放事情,總感覺不踏實,休息也休息不好(悲哀)
突然想到前段時間開發的app,自己控制過android的返回,微信會不會也提供了自定義返回呢,經過一大堆的搜尋,發現js就有能監聽瀏覽器返回的事件(有些知識點不用,慢慢就忘了),兜兜轉轉了一大圈,至少用我的週末幫大家證明了網上說的很多方式行不通,哈哈哈,終極解決,上程式碼(vue的思路)
created () { // 當前需要直接退出的頁面 window.history.pushState(null, null, "") window.addEventListener("popstate", this.popstate, false) }, destroyed: function () { // 記得清除,不然單頁面,其它頁面也可以用 window.removeEventListener("popstate", this.popstate, false) }, methods: { popstate () { wx.closeWindow() // 微信網頁退出 } }