最近因为小程序的火爆,再加上老板的要求。需要搭建并将部分公众号功能开发到小程序,所以自己着手了解并搭建了小程序。(其中跳过很多坑,看过很多博客。希望这个博客可以帮助到同样需求的童鞋把),博主做了一次更新2019.2.18日(解决关于小程序获取不到unionid的问题)
微信小程序和公众号的区别、关联
说起小程序和公众号,其实基本上差不多,都有微信需要的openid,和对应的处理的微信接口(如推送模板消息、支付等都需要对应的openid)最主要的还是unionId(这个需要在开放平台上关联公众号和小程序,才能将两个独立的openId识别出相同的用户,具体可以百度一下,这里不做太多赘述)
微信小程序最重要的一点(!!!)
因为这边博主自己遇到,巨坑的一点。小程序通过公众平台关联公众号的时候。必须使用encryptedData获取,否则只通过code再在后端通过接口直接获取用户信息时,未关注、登录过公众号的小程序获取不到unionid。
获取unionid必须要通过解密encryptedData方式获取到加密的用户数据。
简单说流程:客户端获取使用wx.login+wx.getUserInfo[参数withCredentials: true]再将code(wx.login的返回值)、encryptedData、iv发送到后端;后端操作:使用code获取临时的session_key,再用session_key,encryptedData、iv。解密获取到unionid(这个一定不会空!!!)
封装wx.request并且保持登陆的session,前提:用户已经授权
虽然小程序可以直接获取用户openid作为用户,之后获取用户授权关联unionId的时候再同步数据。为了不操作麻烦,我的设计是在授权之后才能使用对应的功能。
好处:
方便统一处理某些情况,如请求session过期时自动刷新,接口调用失败显示错误信息。简化写法等。这边根据我们的后台业务做了一定的封装,可以借鉴一下
/**
* 初始化方法,包含获取用户信息和登陆后台(项目中所有请求都必须先通过该方法初始化)
* callback 只有用户授权成功并且登陆后才处理回调函数
*/
wxInit: function(callback) {
// 如果还没监测配置成功
if (!this.globalData.hasUserInfo) {
wx.getSetting({
success: res => {
if (res.authSetting['scope.userInfo']) {
// 已经授权,可以直接调用 getUserInfo获取头像昵称,不会弹框
//微信登录
this.wxLogin(null, callback)
} else {
wx.navigateTo({
url: '../userInfo/index'
});
}
}
})
} else {
if (callback && typeof callback === "function") {
callback()
}
}
}
/**
* 封装wx.request
* param obj 正常ajax内对象url,data等
* param acFail方法,当活动返回错误-1时做的操作 func,这边是后台特定业务的返回值,做特殊处理
*/
wxRequest: function(obj, acFail) {
const that = this;
let method = "POST"
//更换请求方式
if (obj.method) {
method = obj.method
}
let header
//根据请求方式,切换内容类型
if (method.toUpperCase() == "GET") {
header = {
'content-type': 'application/json'
}
} else {
header = {
'content-type': 'application/x-www-form-urlencoded'
}
}
//放入服务端session
const sessionId = wx.getStorageSync("sessionId")
if (sessionId) {
header.cookie = 'SESSION=' + sessionId
}
// 封装request
wx.request({
url: getApp().config.apiServer + obj.url,
data: obj.data,
method: method,
header: header,
success: function(res) {
//请求状态不是200现实错误
if (res.statusCode != 200) {
if (obj.fail && typeof obj.fail === "function") {
obj.fail(res);
} else {
wx.showToast({
title: '请求失败,错误' + res.statusCode,
icon: "none"
})
}
return
}
const data = res.data
if (data.status == 2) {
//session过期超时,需要刷新session,并重新调用方法
//判断当前是否是未授权前请求,如果是,则直接返回
wx.getSetting({
success: res => {
if (res.authSetting['scope.userInfo']) {
getApp().wxLogin(obj)
} else {
//未授权请求
console.log("未授权请求" + obj.url)
}
}
})
} else if (data.status == 1) {
wx.showToast({
title: data.msg,
icon: "none",
duration: 2000
})
console.log("error_url:", obj.url)
console.log("err_msg:", data.msg)
} else if (data.status == -1) {
//定义活动失败操作
if (acFail && typeof acFail === 'function') {
acFail()
}
} else {
obj.success(data);
}
},
fail: function(res) {
if (obj.fail && typeof obj.fail === "function") {
obj.fail(res);
}
}
})
}
其中有对错误情况的统一处理,重要的还是对session过期的处理,d=====( ̄▽ ̄*)b
/**
* 微信登录方法,获得code更新后台session
* userInfo 用户信息对象
* callbackObj 请求过期时需要重新执行的请求参数
* action 登录成功之后要做的事情
*/
wxLogin: function(callbackObj, action) {
wx.login({
success: res => {
const code = res.code
wx.getUserInfo({
withCredentials: true,
lang: "zh_CN",
success: res => {
getApp().globalData.hasUserInfo = true
const userInfo = res.userInfo
getApp().globalData.userInfo = res.userInfo
res.rawData = ""
const jsonStr = JSON.stringify(res)
//正式登陆
getApp().wxRequest({
url: "tokenHandle/smallProgramLogin",
data: {
code: code,
loginType: 1,
jsonStr: jsonStr
},
success: function(res) {
if (res.status == 0) {
wx.setStorageSync("sessionId", res.data.sessionId)
wx.setStorageSync("isMember", res.data.isMember)
wx.setStorageSync("memberNum", res.data.memberNum)
if (res.data.isMember == "true") {
wx.setStorageSync("user", res.data.unionid)
} else {
wx.removeStorageSync("user")
}
wx.setStorageSync("userSign", res.data.unionid)
//如果有该对象,表示之前session过期,并且需要重新执行请求
if (callbackObj) {
getApp().wxRequest(callbackObj)
}
if (action && typeof action === 'function') {
action()
}
}
console.log(res)
}
})
// 所以此处加入 callback 以防止这种情况
if (this.userInfoReadyCallback) {
this.userInfoReadyCallback(res)
}
}
})
}
})
}
知识点:
1.wx.login()
调用接口获取登录凭证(code)进而换取用户登录态信息,包括用户的唯一标识(openid) 及本次登录的 会话密钥(session_key)等。
2.封装request中的回调函数的使用和其中:请求过期后重新登陆需要再次执行一次过期的request