Vue微信公衆號開發踩坑記錄

需求

  • 微信受權登陸(基於公衆號的登陸方案)
  • 接入JS-SDK實現圖片上傳,分享等功能

現狀及難點

  • 採用的Vue框架,先後端分離模式(vue工程僅做爲客戶端),用戶經過域名訪問的是客戶端,可是微信受權中涉及簽名和token校驗依賴服務端
  • JS-SDK須要向服務端獲取簽名,且獲取簽名中須要的參數包括所在頁面的url,但因爲單頁應用的路由特殊,其中涉及到iOS和android微信客戶端瀏覽器內核的差別性致使的兼容問題

解決方案

受權登陸

本人將受權流程設計以下:
此處輸入圖片的描述
詳細說明:vue

  1. 用戶訪問網站主域名
  2. vue客戶端(domain/)接收請求,在路由解析前判斷用戶是否登陸(好比檢查cookie);
  3. 若是沒有登陸,則經過api獲取微信受權地址,獲取後跳轉到微信受權頁面;
  4. 用戶確認受權,微信服務器發起回調請求,這時回調到服務器端(domain/api/xxx)
  5. 服務器端保存用戶信息,進行註冊登陸操做(記錄cookie),重定向到vue客戶端(domain/)
  6. 重複第一步,受權登陸成功

踩坑記錄:
如下是另外一個受權方案
此處輸入圖片的描述
其實若是隻實現受權登陸到話,這個方案是能夠的,並且也很清晰,vue客戶端單方面在服務器和微信服務器之間進行通訊,微信服務器不能直接和服務器通訊。這種方案的坑在於當微信受權回調時會攜帶一個code參數,該參數會污染vue路由致使ios上進行JS-SDK簽名時失敗(後續會具體描述這個問題)android

JS-SDK簽名

對於簽名,官方是這麼說的ios

全部須要使用JS-SDK的頁面必須先注入配置信息,不然將沒法調用(同一個url僅需調用一次,對於變化url的SPA的web app可在每次url變化時進行調用

vue中路由有history和hash兩種模式;在history模式下,理想的設計方案是,當進入到須要用到JS-SDK組件時,獲取如下當前url(也就是經過 location.href.split(‘#’)[0]得到到的地址)傳遞到服務端進行簽名,應該就沒問題了,可是IOS獲取的url並非調用微信js的時候所在頁面的地址,而是進入到網站第一個頁面的地址。 web

網上查詢到一個方案是針對ios設備進入頁面時先將當前url記錄下來,到受權頁面時將記錄的url傳遞給服務端進行簽名。該方案經實踐是可行的,媽媽不再用擔憂個人網址很醜很難看啦。vue-router

另一個方案就是使用hash模式,這種模式下,url永遠都只是主域名地址,省去了傳遞url的煩惱,也不必處理兼容,因此若是不建議路由中有#的話,該方案應該是首選方案。vuex

這裏還有一個深坑,那就是若是受權方案採用了上述中的vue客戶端處理回調的方式,那麼ios將永遠沒法簽名成功,爲何呢,由於這種方案路由一般是這樣子的:axios

http://domain.com/?code=xxxxxx&stat=#/xxx

這種路由中帶了參數的url是無法簽名校驗成功的!
這種路由中帶了參數的url是無法簽名校驗成功的!
這種路由中帶了參數的url是無法簽名校驗成功的!
重要的事情得說三遍啊
在我另一篇文章中對js-sdk簽名作了更多的介紹,能夠移步到vue微信公衆號開發踩坑記錄(2)segmentfault

Coding

任何不上代碼的吹逼都是耍流氓,這裏筆者分享下在vue中具體怎麼coding的。後端

微信受權登陸

筆者在項目中使用的vue-router進行路由控制,使用了vuex記錄用戶登陸信息,可是因爲vuex中存儲的內容在頁面刷新後會丟失,因此服務端同時也寫了用戶登陸狀態到cookie中,vue中須要經過這兩個條件進行登陸判斷,很少BB,直接看代碼吧api

// ... other code

router.beforeEach((to, from, next) => {
  if ((!VueCookie.get('user') && !store.state.userInfo)) {
    // 第一次訪問
    console.log('受權登陸')
    // 跳轉到微信受權頁面,微信受權地址經過服務端得到
    axios.post('/api/login').then(res => {
      var data = res.data
      if (data.code === 100) {
        window.location.href = data.data
      }
    })
  } else if (!store.state.userInfo) {
    // 刷新頁面,獲取數據存入vuex
    axios.get('/api/currentuser').then(res => {
      if (res.data.code === 100) {
        store.dispatch('setUserInfo', res.data.data)
        next()
      }
    })
    console.log('cookie生效期內登陸')
    next()
  } else {
    // 已經登陸
    console.log('已登陸')
    next()
  }
})

//... other code

history模式下的JS-SDK簽名

在入口文件中將當前url存入vuex

// ... other code
router.beforeEach((to, from, next) => {
  document.title = to.meta.title
  // 處理jssdk簽名,兼容history模式
  if (!store.state.url) {
    store.commit('setUrl', document.URL)
  }
  // ... other code

在須要獲取簽名的組件中獲取並進行配置

// ... other code
created () {
      var sef = this
      var url = ''
      // 判斷是不是ios微信瀏覽器
      if (window.__wxjs_is_wkwebview === true) {
        url = this.$store.state.url.split('#')[0]
      } else {
        url = window.location.href.split('#')[0]
      }
      this.$http.get('/api/jssdk?url=' + url).then(function (res) {
        sef.lists = res.data.data
        hmTools.wechact(sef.lists, sef) //js-sdk配置
      })
    }
// ...other code

結語

因爲本人文筆通常,思惟的表達估計不到位,看法也是淺嘗輒止,因此若是看官您有疑惑的地方或者有歧義歡迎來和本人交流。爲了方便你們互相溝通,本人也建立了一個vue公衆號開發的qq羣,歡迎加入和你們一塊兒分享開發心得,qq羣號:130903919

相關文章
相關標籤/搜索