时间:2022-08-06 20:03:01 | 来源:网站运营
时间:2022-08-06 20:03:01 来源:网站运营
本篇手记,旨在解决微信跨产品链路中的用户资料种种痛点,业务场景解惑与技术实现细节并存,约 4000 字,请耐心阅读。这几年的社交,是微信的社交
这几年的微信开发,是基于微信公众号的开发
这几年的公众号还没折腾明白,小程序便迫不及待扑面而来
这几年的挣扎开发历程,总是漫不经心却时光飞逝的几年...
公众号调用各接口时都需使用access_token。开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效我们从中可以得到如下几条信息:
const API = '微信全局 access_token API'export async getToken() { let data = await fetchTokenFromDbOrAPI() let now = (new Date().getTime()) if (data.expires > now / 1000) { return data } // 票据过期 重新获取 data = await updateToken() // 设置到期时间 now = (new Date().getTime()) data.expires = now / 1000 + data.expires_in // 入库或同步给某个服务 await saveTokenToDbOrAPI(data) return data}export async updateToken() { const data = await request(API) return data}
官方文档中还有这样一句话:在刷新过程中,中控服务器对外输出的依然是老access_token,此时公众平台后台会保证在刷新短时间内,新老access_token都可用,这保证了第三方业务的平滑过渡保证在刷新短时间内 是一个什么概念呢,刷新要多久,是 100 毫秒,还是 2 秒?刷新动作发起的时时候到收到请求存入到数据库,到能对外提供服务,这中间如果有其他的用户请求触发了再次刷新,那么需要在服务器端做已发出刷新动作的统计么,需要加锁 hold 住拦截当前的刷新动作么,需要一直等到上一个刷新成功返回且存入数据库再清空刷新队列么。
export async getToken() { let data = await fetchTokenFromDbOrAPI() let now = (new Date().getTime()) if (data.expires > now / 1000) { return data } // 票据过期 重新获取 data = await updateToken() // 设置到期时间,并缩短 10 分钟 now = (new Date().getTime()) - 600 * 1000 data.expires = now / 1000 + data.expires_in // 入库或同步给某个服务 await saveTokenToDbOrAPI(data) return data}
好,我们搞定了 公众号的全局唯一接口调用凭据, 我们有资格去请求用户资料了。获取关注粉丝基本信息: 未获得
获得条件:必须通过微信认证
网页授权获取用户基本信息: 未获得
获得条件:必须通过微信认证
获取关注粉丝基本信息: 已获得
每日上限:500000 次
网页授权获取用户基本信息: 未获得
获得条件:必须是服务号+必须通过微信认证
获取关注粉丝基本信息: 未获得
获得条件:必须通过微信认证
网页授权获取用户基本信息: 未获得
获得条件:必须通过微信认证
获取关注粉丝基本信息: 已获得
每日上限:500000 次
网页授权获取用户基本信息: 已获得轰轰烈烈的 8 种情况,就问你怕不怕。
每日上限:无上限
const message = { ToUserName: 'gh_c69edc91fe37', FromUserName: 'oW4nAvpSgoLKfVDdtK_VvGutDako', CreateTime: '1500037104', MsgType: 'text', Content: 'uu', MsgId: '6442610305031245235'}
拿到后,无论在认证过的订阅号还是认证过的服务号中,就可以获取关注公众号的粉丝资料了,祭出代码:const userAPI = '微信用户基本信息 API'export async getUserInfo(openID) { const data = await getToken() const token = data.access_token const openID = message.FromUserName const url = `${userAPI}?access_token=${token}&openid=${openID}` const userData = await request(userAPI) return userData}
似乎一切顺风顺水,那是因为关注过公众号的粉丝,在向我们推送消息时候,消息中已经包含了 openID 了,所以拼接个 url 请求就好了,但是网页中用户资料的获取就是另外一回事了。const userSNSAPI = '微信 SNS 用户资料 API'const authAPI = '微信 OAuth 2.0 API'const tokenAPI = '微信网页授权 access_token API'// 此票据并不是前面的 公众号的全局唯一接口调用凭据export async getToken(code) { let data = await fetchTokenFromDbOrAPI() let now = (new Date().getTime()) if (data.expires > now / 1000) { return data } // 票据过期 重新获取 data = await updateToken() // 设置到期时间,并缩短 10 分钟 now = (new Date().getTime()) - 600 * 1000 data.expires = now / 1000 + data.expires_in // 入库或同步给某个服务 await saveTokenToDbOrAPI(data) return data}// 拼接一个微信域名的 URL B,参数放上我们真正想要跳转的 URL C// 用户打开 URL B,再点击授权按钮(微信自动展现不需我们关心),跳到 URL Cexport function oAuthURL(scope, redirect, state) { const url = encodeURIComponent(redirect) return `${authAPI}?appid=${ID}&redirect_uri=${url}&response_type=code&&scope=${scope}&state=${state}#wechat_redirect`}// http://x.o/redirect/a// 用户进入 URL A,被你偷偷换成 Bexport async visitPageA(ctx, next) { const scope = 'snsapi_userinfo' const redirect = 'http://x.o/redirect/c' const state = 'abc' const url = oAuthURL(scope, redirect, state) ctx.redirect(url)}// http://x.o/redirect/c?code=xo&state=abc// 用户进入 URL C,被你偷偷拿到 code 换数据export async visitPageC(ctx, next) { // 拿到 state 就拿到了跳转之前用户的所在状态 // const state = ctx.query.state const code = ctx.query.code const data = await getToken(code) const openID = data.openid const url = `${userSNSAPI}?access_token=${token}&openid=${openID}` const userData = await request(url) // 拿到 userData 做其他业务...}
好,总算是能拿到用户信息了,松了一口气,结果产品经理跑过来,气喘吁吁的说,兄弟兄弟,快醒醒,咱们要上小程序了,这是需求清单,照着公众号网页 App 的功能实现就行啊......// http://x.o/redirect/c?code=xo&state=abc// 用户进入 URL C,被你偷偷拿到 code 换数据export async visitPageC(ctx, next) { // 拿到 state 就拿到了跳转之前用户的所在状态 // const state = ctx.query.state const code = ctx.query.code const data = await getToken(code) // openid 可以获取后,跟既有数据库里的 openid 比对 // 比对上,就把之前的 openid 逻辑逐步干掉,替换成 unionid // const openID = data.openid // 从此拿 unionID 来请求用户信息即可 const unionID = data.unionid const url = `${userSNSAPI}?access_token=${token}&openid=${unionID}` const userData = await request(url) // 拿到 userData 做其他业务...}
export const getUserByCode = async code => { const options = { uri: 'https://api.weixin.qq.com/sns/jscode2session', qs: { appid: 'appid', secret: 'secret', js_code: code, grant_type: 'authorization_code' }, json: true } const userData = await request(options) return userData}// 收到小程序端发过来的请求,解析 UserInfoexport async getMinaUer(ctx, next) { const userInfo = ctx.query.userInfo const code = ctx.query.code const userData = await getUserByCode(code) const wxBizDataCrypt = new WXBizDataCrypt(userData.session_key) const decryptData = wxBizDataCrypt.decryptData(userInfo.encryptedData, userInfo.iv) // 解析出来 unionid const unionid = wxBizDataCrypt.unionid // ...}
于是宣告一统天下:作者: Scott
链接:https://www.imooc.com/article/19204
来源:慕课网
本文原创发布于慕课网 ,转载请注明出处,谢谢合作!
关键词:程序,用户,获取,资料,公众