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

相关文章
相关标签/搜索