【2022微信小程序排雷】云开发和非云开发环境下如何正确获取openid?

前言

最近在整理我的第一个小程序项目,发现了一些Bug。在这里记录解决过程,一方面梳理知识,另一方面帮大家排排雷。

正文

1、遇错纠正过程

在小程序开发时,我们常常会调用wx.loginwx.getUserProfile来让用户授权并收集用户的openid、用户名、头像等信息。

官方文档对这两个接口的描述如下

  • wx.login(Object object) (不支持以 Promise 风格 调用)

调用接口获取登录凭证(code)。通过凭证进而换取用户登录态信息,包括用户在当前小程序的唯一标识(openid)、微信开放平台帐号下的唯一标识(unionid,若当前小程序已绑定到微信开放平台帐号)及本次登录的会话密钥(session_key)等。用户数据的加解密通讯需要依赖会话密钥完成。

  • wx.getUserProfile(Object object) (支持以 Promise 风格 调用)

获取用户信息。页面产生点击事件(例如 button 上 bindtap 的回调中)后才可调用,每次请求都会弹出授权窗口,用户同意后返回 userInfo。

这样看是不是感觉两者没有什么联系,先后顺序不影响,我最开始也是这样觉得的,代码如下

getInfo(){
  wx.getUserProfile({
     desc: '登录',
     success: (res) => {
       console.log('getUserProfile', res)
       let changeData = {}, // 需要setData的数据, 一次setData的操作
          userInfo = {
            username: res.userInfo.nickName,
            userphoto: res.userInfo.avatarUrl
          }
        changeData.hasUserInfo = true
        wx.login({
          //成功放回
          success: (res) => {
            let code = res.code
            wx.request({
              url: `https://api.weixin.qq.com/sns/jscode2session?appid=${appid}&${this.data.my.lock}=${this.data.my.key}&js_code=${code}&grant_type=authorization_code`,
              success: (res) => {
                userInfo.openid = res.data.openid
                changeData.userInfo = userInfo
                this.setData(changeData)
                app.globalData.openid = res.data.openid;
                wx.setStorageSync('userInfo', userInfo)
                db.collection('users')
                .where({
                  openid:res.data.openid
                })
                .get().then((res)=>{
                  if(res.data.length===0){
                  db.collection('users').add({
                    data: {
                      ...this.data.userInfo
                    }
                  })
                  db.collection('userData').add({
                    data:{
                      openid:res.data.openid,
                      late:0,
                      notCome:0,
                      cancel:0,
                      leaveEarly:0,
                      signIn:0
                    }
                  }) 
                  }
                })
            
              }
            })
          }
        })
     }
   })
 
  },

在微信开发者工具和真机调试时可以成功,但是预览就无法授权成功。

最开始以为是微信小程序的Bug,用朋友手机试了一下体验版,还是无法授权成功。🆗,那应该是我的问题,尝试使用手机调试,发现调试的时候又可以授权成功了,在日志里也可以打印并获取到的userInfo

我不明白,但是我一整个震惊住了!又看了一遍代码,感觉是wx.login 和 wx.getUserProfile的问题,上网查了一下,发现还真是!!!

在这里插入图片描述

也就是说,我们必须先调用wx.login拿到最新的code,否则容易解密失败。即保证wx.login是比wx.getUserProfile先完成。直接把wx.getUserProfile放在wx.login的回调里不就好了嘛?

NO!!! wx.getUserProfile在页面产生点击事件(例如 button 上 bindtap 的回调中)后才可调用,不可放回调里。

网上的promise.all的方式处理,我没试但是我感觉是不行的。all只是把login和getinfo同时运行罢了,但是这两个实际都是异步,到底哪个先触发实际是没法确定的。

找了很久的资料没有答案,最后问了两个专门做微信小程序开发的前辈,发现大家都是这样解决的!!!

因为code有时效,所以一般都是进入页面的时候直接调用wx.login获取code,然后用code换取openid,存储openid。当用户点击授权按钮时,我们可以直接调用wx.getUserProfile。

代码修改如下:

var openid='';  // 不渲染到页面所以不要存在data中

 onLoad(options) {
  var t = this
  var userInfo = wx.getStorageSync('userInfo')
   if(userInfo){
    this.setData({
      userInfo:userInfo,
      hasUserInfo:true,
    })
   }else{
    db.collection('importantKey')
    .get()
    .then((res)=>{
      var my = {...res.data[0]} // 密钥不能以明文形式写,所以存在数据库中获取
      wx.login({
        //成功放回
        success: (res) => {
          let code = res.code
          wx.request({
            url: `https://api.weixin.qq.com/sns/jscode2session?appid=${appid}&${my.lock}=${my.key}&js_code=${code}&grant_type=authorization_code`,
            success: (res) => {
              openid = res.data.openid
            }
          })
        }
      })
   })
  }
},

getInfo(){
  var changeData = {}// 需要setData的数据, 一次setData的操作,优化性能
  wx.getUserProfile({
     desc: '登录',
     success: (res) => {
        var userInfo = {
            username: res.userInfo.nickName,
            userphoto: res.userInfo.avatarUrl,
            openid:openid
          }
        changeData.hasUserInfo = true
        changeData.userInfo = userInfo
        this.setData(changeData)  // 一次性setData
        wx.setStorageSync('userInfo', userInfo)
        db.collection('users')
        .where({
          openid:userInfo.openid
        })
        .get().then((res)=>{
          console.log('openid',openid);
          if(res.data.length===0){
          db.collection('users').add({
            data: {
              ...userInfo
            }
          })
          db.collection('userData').add({
            data:{
              openid:userInfo.openid,
              late:0,
              notCome:0,
              cancel:0,
              leaveEarly:0,
              signIn:0
            }
          }) 
          }
        })
     }
   })
 
  },

你以为这样就对了吗?错!!!

如果直接这样使用,你就会发现微信小程序的另外一个新坑

就是在小程序开发者工具直接测试,使用真机调试,都没有任何问题,但是一旦上传代码,使用小程序的体验版测试的话,就拿不到openid,奇怪的是,如果在体验版开启调试模式,又可以拿到。也就是说开发环境和生产环境在代码相同的情况下,体现的效果不一样
在这里插入图片描述

经过很长时间的查找资料,获取openid不能直接在微信客户端来获取,因为api.weixin.qq.com写到域名配置里面是无效的,必须后端调用。应该改用后端来获取openid然后再返回给前端。
在这里插入图片描述

2、总结

非云开发

如果不是云开发,在onLoad的时候直接调用wx.login获取code,然后传给后端,让后端获取openid返回给前端

云开发

如果是云开发的话,可以直接创建一个云函数getopenid
在这里插入图片描述
index.js代码如下

// 云函数入口文件
const cloud = require('wx-server-sdk')

cloud.init()

// 云函数入口函数
exports.main = async (event, context) => {
  const wxContext = cloud.getWXContext()

  return {
    event,
    openid: wxContext.OPENID,
    appid: wxContext.APPID,
    unionid: wxContext.UNIONID,
  }
}

在授权页面中onLoad函数函数调用

var openid='';  // 不渲染到页面所以不要存在data中

 onLoad(options) {
  var t = this
  var userInfo = wx.getStorageSync('userInfo')
   if(userInfo){
    this.setData({
      userInfo:userInfo,
      hasUserInfo:true,
    })
   }else{
   wx.cloud.callFunction({ //  调用云函数获取openid
    name: 'getopenid',
    complete: res => {
      openid = res.result.openid;
    }
  })
  }
},

如果觉得本篇文章对你有帮助,记得点赞、收藏~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

焦妮敲代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值