ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

微信小程序获取微信运动步数:授权、AES解密与后端实践

微信小程序获取微信运动步数:授权、AES解密与后端实践 简介微信运动步数获取的小程序实现源码包专为小程序开发者解决 wx.login 登录态获取、wx.getWeRunData 运动数据采集以及 WXBizDataCrypt 加密数据解密的完整链路同时给出 wx.getSetting、wx.openSetting、wx.authorize 等授权衔接建议适合健康类小程序开发或学习微信开放能力者参考。包内共 3 个文件以 HTML 入口文件为主辅以 InsCode 项目配置与 .gitignore 规则文件可方便地在对应环境中直接运行、调试与版本管理。整个压缩包仅 9KB文件结构非常精简适合快速阅读和改造。目前已有 158 人浏览学习对想快速跑通微信运动步数功能、降低踩坑成本的开发者而言是一份轻量而实用的参考源码。1. 小程序获取微信运动步数这块硬骨头授权、加密与验签一个都躲不开做运动打卡、每日步数排行、健康激励这类小程序第一道坎就是微信运动步数。小程序里确实有wx.getWeRunData这个官方接口但它返回给你的不是{ step: 12345 }这种明文字段而是一段 AES 加密的encryptedData配套一个iv。想看到明文步数你必须自己搭后端用wx.login换来的session_key去解密还要校验数据里的 watermark 水印。这套流程从授权弹窗到服务端解密环环相扣漏一环就看不到步数。我把一套可运行的最小工程拆开讲前端、后端、参数、坑一次说清楚适合正在做小程序运动类功能、或者第一次接微信开放数据的从业者照着复现。2. 微信运动步数的数据链路从用户授权到后端解密的必经之路先把这个功能的数据流完整串一遍后面写代码时你才知道每段代码站在链路的哪个位置。整体是用户点击授权按钮 - 小程序wx.login拿到 code - 前端wx.getWeRunData拿到 encryptedData 和 iv - 前端把 code、encryptedData、iv 一起 POST 给后端 - 后端用 code 调 code2Session 换取 session_key - 后端用 session_key 和 iv 解出明文 - 返回stepInfoList给前端渲染。下面把每个环节拆开重点讲机制设计的意图理解了意图后面遇到报错才有排查方向。2.1 为什么 wx.getWeRunData 返回的是加密数据而不是明文步数微信开放数据微信运动步数属于用户隐私数据的设计原则是前端不直接接触明文避免被客户端抓包工具截获后批量获取用户健康数据。wx.getWeRunData的 success 回调里只有三样东西encryptedData加密串、iv初始向量、cloudID云开发环境下才有。加密串是用当前用户的session_key经过 AES-128-CBC 加密的敏感数据里面才是步数列表。这样设计的好处是即使有人用抓包工具把前端请求原样截走拿不到 session_key 也解不开密文相当于给数据加了一道黑匣子防护。代价就是前端工程师只调wx.getWeRunData是看不到步数的必须把 encryptedData 和 iv 交给后端处理。那解密之后里面到底是什么结构是这样的{ stepInfoList: [ { step: 852, timestamp: 1445866601 }, { step: 1520, timestamp: 1445866602 } ], watermark: { appid: wx1234567890abcdef, timestamp: 1445866601 } }其中step是当天总步数timestamp是 UTC 秒级时间戳微信返回最近 30 天数据每天一条。watermark里的appid是数据归属方标识timestamp是加密时间。前端拿不到明文后端解出来是这么一坨 JSON。为什么用 session_key 而不是 appsecret 直接加密因为 session_key 是每个用户、每次会话独立的后端的 appsecret 是全局的。如果拿全局密钥加密所有用户的行为数据密钥一旦泄露所有用户的数据都裸奔session_key 粒度到会话泄露一个只会影响一个用户的一个时间段可控得多。小程序所有开放数据接口都统一走这套体系步数、手机号、用户信息一视同仁先把这套逻辑吃透后面接任何getXxx开放数据都不慌。2.2 session_key 与 code2Session前端拿不到解密密匙的机制设计session_key 在前端是拿不到的它藏在 code2Session 接口的响应里。小程序前端调wx.login()会得到一个一次性凭证code前端把 code 传给自己的后端后端拿 code 去调微信的auth.code2Session接口用 appid、appsecret、code 三件套换取openid和session_key。微信官方明确规定session_key 不允许下发到前端只能保存在后端。下面这段是 Node.js 里最简洁的换取写法const resp await axios.get(https://api.weixin.qq.com/sns/jscode2session, { params: { appid: APPID, secret: SECRET, js_code: code, grant_type: authorization_code } }) if (resp.data.errcode) { throw new Error(code2Session failed: ${resp.data.errmsg}) } const { openid, session_key } resp.data这里的grant_type固定填authorization_codejs_code是前端传来的 codeappid是你的小程序 appidsecret在小程序后台的“开发 - 开发管理 - 开发设置”里获取。注意这个接口返回的 session_key 是 base64 字符串不要打印到日志里更不要下发到前端。接着是 session_key 的生存期规则这部分很多人吃过亏。第一每次wx.login都意味着一个新的 code换出来的 session_key 会让旧 key 在短时间内失效所以不能拿旧密文配新 code解密必败。第二session_key 没有官方承诺的固定过期时长微信只暗示“用户长时间不用可能失效”。第三同一用户的并发请求如果每次都重新换 key后完成的请求可能覆盖先完成的 key导致先发的请求解密失败。所以后端一般会把openid - session_key缓存起来具体缓存策略我在第 6 章展开。2.3 三条落地路线怎么选纯前端、自建后端、云开发接微信运动步数常见做法有三条路线。纯前端路线前端拿 encryptedData 后直接在本地解密这在微信禁止下发 session_key 的大前提下是站不住的审核和稳定性双输属于为了省事给自己埋雷我不建议这么做。第二条是自建后端或云服务器前端wx.login拿 code后端调 code2Session 换 session_key再解密。这是最正统、信息最透明的方案适合有自己服务端的小程序团队。缺点是要处理 key 缓存、解密库依赖以及小程序后台的服务器域名白名单配置。第三条是微信云开发用wx.getWeRunData返回的cloudID字段在云函数里通过开放能力直接拿明文省掉自己解密。对没有后端、想快速上线的项目非常友好但云开发本身是独立的付费环境openapi 调用有频率限制。下面这张对比表是我选型时常用的判断依据路线解密位置需要的额外组件适用场景主要顾虑纯前端前端无不推荐session_key 不能下发审核不过自建后端后端一台服务器 合法域名大部分商业小程序密钥缓存与过期处理要自己做云开发云函数云开发环境试用、个人项目、快速上线收费、openapi 有配额我的建议很直接如果你的项目已经有后端别绕远路直接用自建后端。你后面大概率还要做步数排行、积分兑换这类业务总归要有个服务端来算逻辑如果只是个人作品、想让页面能显示步数云开发最快前端代码里甚至不需要出现 encryptedData 的身影。3. 跑通最小可运行源码小程序前端 Node.js 解密服务3.1 工程结构与 app.json / 权限声明先给出一套可以直接跑的最小工程结构。前端用原生小程序后端用 Node.js 的 Express解密依赖用 Node 内置的crypto模块不需要引入额外的大包。miniprogram/ app.js app.json pages/ index/ index.wxml index.wxss index.js server/ package.json app.js lib/ decrypt.jsapp.json里不需要专门声明运动步数权限scope.werun的声明方式是调用接口时由按钮触发授权。但基础配置要合理下面是app.json的最小配置{ pages: [ pages/index/index ], window: { navigationBarTitleText: 微信运动步数 }, style: v2, lazyCodeLoading: requiredComponents }说明lazyCodeLoading不是运动步数的必要条件但新版基础库推荐配置。真正和步数相关的是pages/index页面里要写的授权按钮以及按钮上声明的scopescope.werun。如果你用的是 uniapp 工程注意 uniapp 的 vue 模板同样支持 button 的open-typegetAuthorize只是scope属性要绑定成scopescope.werun其它逻辑可以原样平移。3.2 授权与拉取步数的完整页面逻辑页面逻辑分三步检查授权状态 - 引导授权 - 拉取并上传加密数据。先看index.wxmlview classcontainer button wx:if{{!isAuthorized}} typeprimary open-typegetAuthorize bindgetauthorizeonAuthorize scopescope.werun 授权微信运动步数 /button button wx:elif{{!hasData}} typedefault bindtapgetStepData 拉取步数 /button view wx:else text今日步数{{todayStep}}/text /view /view注意open-typegetAuthorize配合scopescope.werun点按钮会直接弹授权框用户点“允许”后触发bindgetauthorize事件。这里不用wx.authorize是因为wx.authorize在用户拒绝过一次之后就不会再弹窗体验上容易卡死用 button 的getAuthorize可以配合后续的引导逻辑反复触发。再来看index.js的完整逻辑Page({ data: { isAuthorized: false, hasData: false, todayStep: 0 }, onLoad() { this.checkAuth() }, checkAuth() { wx.getSetting({ success: (res) { if (res.authSetting[scope.werun]) { this.setData({ isAuthorized: true }) this.fetchAndUpload() } else { this.setData({ isAuthorized: false }) } } }) }, onAuthorize(e) { if (e.detail.errMsg.includes(ok)) { this.setData({ isAuthorized: true }) this.fetchAndUpload() } }, fetchAndUpload() { wx.getWeRunData({ success: (res) { wx.login({ success: (loginRes) { wx.request({ url: https://your-server.com/api/decrypt, method: POST, data: { code: loginRes.code, encryptedData: res.encryptedData, iv: res.iv }, success: (resp) { const stepInfoList resp.data.stepInfoList || [] const today this.normalizeDate(new Date()) const todayItem stepInfoList.find(item { return this.normalizeTimestamp(item.timestamp) today }) this.setData({ hasData: true, todayStep: todayItem ? todayItem.step : 0 }) }, fail: (err) { console.error(decrypt fail, err) } }) } }) }, fail: (err) { console.error(getWeRunData fail, err.errMsg) } }) } })注意一个细节wx.getWeRunData和wx.login是两个独立的异步请求返回顺序没有保证。上面先拿步数再登录也有反过来的写法。实际经验是两者谁先谁后不影响结果但必须都成功后再把 code 和加密数据一起发给后端少一个都不行。这里的url要填你自己的服务器地址而且必须在小程序后台的“开发设置 - 服务器域名”里配置好 request 合法域名否则开发工具里直接报url not in domain list。这是新手的第一个翻车点。补一个参数说明normalizeTimestamp是把接口返回的 UTC 秒级时间戳转成本地日期的函数item.step是当天总步数。这个转换在真实设备上是必须做的否则安卓和 iOS 看到的“今天”可能差出一天第 4 章我会单独讲。3.3 Node.js 端 code2Session 与 AES 解密实现后端是整个方案的核心。先看server/app.jsconst express require(express) const axios require(axios) const { decryptWeRunData } require(./lib/decrypt) const app express() app.use(express.json()) const APPID 你的appid const SECRET 你的appsecret const sessionCache new Map() app.post(/api/decrypt, async (req, res) { const { code, encryptedData, iv } req.body if (!code || !encryptedData || !iv) { return res.status(400).json({ error: missing params }) } let sessionKey sessionCache.get(code) if (!sessionKey) { const url https://api.weixin.qq.com/sns/jscode2session const params { appid: APPID, secret: SECRET, js_code: code, grant_type: authorization_code } const resp await axios.get(url, { params }) if (resp.data.errcode) { return res.status(400).json({ error: resp.data.errmsg }) } sessionKey resp.data.session_key sessionCache.set(code, sessionKey) } try { const result decryptWeRunData(sessionKey, encryptedData, iv, APPID) res.json(result) } catch (e) { res.status(400).json({ error: e.message }) } }) app.listen(3000, () console.log(server on 3000))注意这里的sessionCache用code作 key这是故意的。每个 code 只对应一个 session_key同一个 code 只能用一次用 code 做 key 不会把新 code 覆盖旧 code 导致并发错乱。更正式的做法是用 openid 做 key但最小示例用 code 更直观。decrypt.js是解密核心const crypto require(crypto) function decryptWeRunData(sessionKey, encryptedData, iv, appid) { // 1. 把 base64 编码的密文和 iv 转成 Buffer const sessionKeyBuf Buffer.from(sessionKey, base64) const encryptedBuf Buffer.from(encryptedData, base64) const ivBuf Buffer.from(iv, base64) // 2. AES-128-CBC 解密密钥长度 16 字节 const decipher crypto.createDecipheriv(aes-128-cbc, sessionKeyBuf, ivBuf) decipher.setAutoPadding(true) // PKCS7 填充由 OpenSSL 自动处理 let decoded decipher.update(encryptedBuf, null, utf8) decoded decipher.final(utf8) // 3. 解析 JSON 并校验数据水印 const data JSON.parse(decoded) if (data.watermark data.watermark.appid ! appid) { throw new Error(watermark appid mismatch) } return data } module.exports { decryptWeRunData }这段代码有五个细节值得强调第一sessionKey、encryptedData、iv全部是 base64 字符串必须先用Buffer.from(x, base64)转成 Buffer直接用字符串当密钥会报Invalid key length。第二AES 模式是aes-128-cbc密钥长度正好 16 字节也就是 session_key 解码后的长度。如果报错Invalid key length先检查 sessionKey 是不是被截断了。第三decipher.final(utf8)必须在update之后调用顺序反了拿不到完整明文。第四开启setAutoPadding(true)让 OpenSSL 处理 PKCS7 填充微信的敏感数据是 PKCS7 填充的不需要手动处理。第五解密后的 JSON 里watermark.appid必须和你的 appid 一致不一致说明解密用的密钥不对或者数据根本不是发给你的。这个校验一定不能省。3.4 本地联调的步骤与预期输出代码写完后联调步骤是这样的。第一步在开发者工具里用测试号或已认证的小程序 appid 打开工程。第二步点“授权微信运动步数”按钮工具里会弹授权框。第三步开发者工具里的“普通编译”模式下wx.getWeRunData会返回模拟数据wx.login会返回一个真实有效的 code。第四步后端跑node server/app.js本机监听 3000 端口把开发者工具里的“不校验合法域名”勾上让前端请求能打到 localhost。预期输出后端打印server on 3000前端页面显示今日步数。一切正常的话第一次联调 10 分钟就能跑通。最容易翻车的点是“不校验合法域名”这个开关——开发工具默认会拦截非 https 请求把它勾上才能访问本地服务但这个开关只在开发调试时用上线前必须换成正式 https 域名。4. 解密细节与参数边界AES-128-CBC 里容易记错的几个地方4.1 密钥、iv、密文的字节序与编码微信运动步数的解密本质是用 session_key 做密钥、用接口返回的 iv 做初始向量对 encryptedData 做 AES-128-CBC 解密。看起来简单实际参数细节能卡住很多人。首先要统一编码。encryptedData和iv在小程序前端是 base64 字符串session_key在后端从 code2Session 拿到时也是 base64 字符串。三者在解密前都要Buffer.from(x, base64)解码成原始字节。如果直接把 base64 字符串当 ASCII 字符串去填密钥长度就不是 16 字节而是 24 字节直接报Invalid key length。这是最常见的低级报错我见过好几个团队在这里卡了一晚上。其次是字节序。所有字段都是网络字节序也就是大端序不需要做任何大小端转换。iv 的长度一定是 16 字节session_key 解码后也一定是 16 字节如果解码后发现长度不对说明 session_key 本身被截断或者有人对 session_key 做了除 base64 解码之外的二次处理。比如把 URL 编码后的 session_key 直接存库取出时没做decodeURIComponent长度就对不上。这里给你一个排查参数是否正确的测试方法找一组你确定能解密的 session_key、encryptedData、iv 三元组单独写一个测试脚本期望解密后的 JSON 里stepInfoList的步数值是你能确认的值。测试脚本和业务代码用同一份解密函数入参全部硬编码。这样业务里出现解密失败时先跑一遍测试脚本能通过说明解密函数没问题问题出在调用方不能通过说明解密函数本身有 bug从函数内部开始查。这个习惯救过我很多次比上线后靠日志猜快得多。4.2 PKCS7 填充与跨端差异AES 是分组加密密文长度必须是 16 字节的整数倍微信在加密时用了 PKCS7 填充。在 Node.js 里用crypto.createDecipheriv默认就是 PKCS7 填充模式但如果你把setAutoPadding(false)打开就必须自己处理填充否则最后一块解密出来会带着0x0b之类的填充字节JSON.parse直接抛异常。有人为了“严谨”自己实现了 PKCS7 反填充结果在整块数据长度刚好是 16 的倍数时反而把最后一个有效字节误删了。我的建议就是别关默认设置PKCS7 让 OpenSSL 处理省心。跨端差异主要体现在数据传递过程中的编码处理。iOS 端某些基础库版本wx.getWeRunData返回的encryptedData里会带有、/等 base64 字符这是正常现象但如果你在传输过程中用了encodeURIComponent而没在后端decodeURIComponent正斜杠变成%2F后端 base64 解码直接失败。血的教训前端往服务器传 encryptedData 和 iv 时不要做额外的 URL 编码直接用wx.request放 JSON body 里传后端用express.json()解析两边都不会碰特殊字符。还有一个差异点容易被忽视真机上wx.getWeRunData的返回时机和开发者工具不同。工具里基本是同步返回真机上偶尔会延迟几百毫秒如果你在onLoad里立即调用并用同步思路处理容易拿到空结果。正确做法是在回调里再判断res.encryptedData是否存在不要假定成功回调一定带数据。4.3 watermark 校验为什么不能省解密成功后JSON 里除了stepInfoList还有一个watermark对象里面是appid和timestamp。appid校验我们已经写进了decrypt.js。timestamp的作用是检测数据是否被重放如果攻击者截获了一次合法请求用同一个 encryptedData 反复打你的后端就能刷出同样的步数。防御的办法是校验watermark.timestamp是否在合理的时间窗口内同时在后端对openid timestamp做幂等去重。在decrypt.js解密成功之后补上这一段const WATERMARK_TTL 60 * 5 // 5 分钟内有效单位秒 if (Math.abs(Date.now() / 1000 - data.watermark.timestamp) WATERMARK_TTL) { throw new Error(watermark timestamp expired) }这段代码有三处容易错第一data.watermark.timestamp是秒级Date.now()是毫秒级必须除 1000 统一单位否则任何一次请求都会被认为“过期”第二时间窗口别设太短用户手机时间和服务器时间可能有几十秒偏移5 分钟是比较稳妥的宽容度第三watermark.appid校验要在timestamp校验之前做因为 appid 错了说明密钥不对后续时间判断没有意义。对于步数这类健康数据这个校验不是可选项按规范来是基本功。4.4 时间戳与数据归一化从 UTC 到本地日期的正确换算stepInfoList里的timestamp是 UTC 秒级时间戳这个时间戳对应的“某一天”是 UTC 日期不是本地日期。如果你的业务只在中国区跑把这两者混用一天两天看不出问题唯独在凌晨 0 点到 8 点这个窗口UTC 还停在昨天本地日期已经是今天直接用 timestamp 去匹配“今日步数”就会匹配到昨天的数据。正确的做法是先把 UTC 时间戳换算成本地日期字符串再拿它和今天日期匹配。new Date(ts * 1000)返回的是本地时区的 Date 对象getFullYear/getMonth/getDate拿到的都是本地日期所以直接这样写就行function timestampToLocalDate(ts) { const d new Date(ts * 1000) const year d.getFullYear() const month String(d.getMonth() 1).padStart(2, 0) const day String(d.getDate()).padStart(2, 0) return ${year}-${month}-${day} }如果你在代码里用了getUTCFullYear或toISOString就又把本地日期拉回 UTC 了等于白换算。这个细节在排行榜业务里尤其要命凌晨排行榜的“今日步数”如果错位用户会看到自己 0 点之前的步数被记到昨天投诉率特别高。数据归一化的另一个注意点是step字段的类型解密后是数字但在某些语言里 JSON 解析后可能带成字符串做比较运算前先转成整数。5. 微信运动步数接入避坑指南从授权失败到数据对不齐的几条血泪记录5.1 授权弹窗不出现getWeRunData 直接进 fail现象button open-typegetAuthorize点击后完全没有弹窗直接回调失败errMsg是getWeRunData:fail auth denied。原因用户之前点过拒绝scope.werun被置为 falsegetAuthorize不再弹窗。另一种是基础库版本低于 2.3.0老版本不支持getAuthorize。解决用wx.getSetting检查授权状态如果authSetting[scope.werun] false引导用户去wx.openSetting重新授权。在checkAuth里加一个分支if (res.authSetting[scope.werun] false) { wx.showModal({ title: 需要运动步数权限, content: 请在设置中开启微信运动步数授权, confirmText: 去设置, success: (r) { if (r.confirm) wx.openSetting() } }) }处理顺序很重要先查getSetting再决定弹哪种授权方式否则就是对着已经拒绝过的用户反复弹无意义的窗。真机调试时用户可以在微信的“设置 - 个人信息与权限 - 授权管理”里找回授权但这个入口太深业务里直接用openSetting引导最直接。5.2 后端解密报 Illegal padding / 40029 无效 code现象后端解密抛error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt或者 code2Session 返回errcode: 40029。原因bad decrypt几乎都是密钥不对最常见是 session_key 和 code 对不上。code2Session 换取的 session_key 随 code 变化前端用了旧的 code 或旧的 session_key解密必然失败。40029是 code 无效或已被使用同一个 code 不能换两次。解决把 code 换 session_key 和解密放在同一个事务里前端每次wx.login后立即换取并解密不要跨请求复用。前端重试时也要重新走wx.login不能拿着失败的参数原样再发一次。另外确认 session_key 存的是 base64 原文别在数据库里被转成 hex 格式十六进制字符串长度 32解码后也不是 16 字节。5.3 安卓当天步数变成昨天现象安卓手机上页面显示的“今日步数”总是比微信运动少一天或者凌晨时段直接显示为 0。原因stepInfoList里每个条目是 UTC 秒级时间戳微信按 UTC 日界归档。东八区用户凌晨 0 点到 8 点之间UTC 日期还是前一天你用本地日期去匹配 timestamp 就会错位。解决匹配今日步数时一定要把 timestamp 转成当地日期再比不能拿 UTC 日期去比。我在第 3 章的normalizeTimestamp就是这个用途。如果业务还涉及别的时区建议统一在服务端按Asia/Shanghai时区算好日期再下发避免每个客户端自己换算出现不一致。5.4 开发版正常、体验版拿不到数据现象开发者工具和开发版都正常体验版一进去就getWeRunData fail或者授权后没有任何数据。原因最常见的是体验版的基础库版本比开发版低代码里用了getAuthorize或其它较新的 API老基础库不支持。另一种可能性是体验成员在小程序后台没配上或权限配置不完整导致部分能力不可用。解决在开发者工具的“详情 - 本地设置”里把调试基础库切到最新稳定版重新编译后上传如果还不行就在小程序后台的“成员管理”里确认体验成员已添加、权限已勾选。体验版和开发版的差异经常让人误以为代码有 bug其实多数是环境配置问题排除顺序应该是基础库版本 - 成员权限 - 网络域名 - 再看代码逻辑。5.5 同一批数据在真机和模拟器差了几千步现象同一账号开发者工具模拟器里显示的步数和真机差了上千步。原因模拟器里的getWeRunData返回的是微信官方给的模拟数据不是真机真实步数这是预期行为。另一个隐蔽原因是真机上微信运动的数据是逐步同步的如果用户当天一直没打开微信步数可能滞后。解决模拟器数据只能用来联调流程不能用业务逻辑依赖它。真机联调时先去微信运动页刷新一次当天步数再回到小程序拉取如果还是对不上让用户确认手机系统设置里“运动与健身”的权限是否对微信开放。安卓各厂商的省电策略也会推迟步数上报这种数据延迟不是小程序代码能解决的需要在 UI 上做说明避免用户误以为是产品 bug。6. 把步数用在业务里按天聚合、排行榜与缓存的正确姿势6.1 stepInfoList 的 30 天窗口与本地时区换算getWeRunData返回的stepInfoList默认包含 30 天左右的数据业务上做“近 7 天走势”时直接从这个数组里取不需要额外调接口。但有两个使用要点一是不要依赖数组是升序还是降序直接按日期匹配最稳妥因为时区会让顺序判断出错二是某些天可能缺失比如用户当天没同步find不到对应日期时要兜底成 0不要让页面渲染出undefined。如果用的是 uniapp 打包同样注意这些逻辑和原生一致。6.2 服务端缓存策略session_key 复用与步数快照如果小程序同时有多个页面要显示步数不要每次都走一遍“解密 - 返回 30 天数据”的全链路。常见做法是后端在用户首次拉取后按openid 日期把明文步数快照存一份比如 Redis 里存key step:{openid}:{date}过期时间设为当天结束下次请求直接读缓存只有缓存失效时才重新触发前端传数据解密。这个策略既能扛住排行榜页面的高频刷新又能减少 code2Session 的调用频率。session_key 本身的缓存要保守一点我习惯设 4 小时过期因为微信官方没有给明确有效期4 小时是“能用且不太旧”的折中值。一旦出现解密失败要立刻清掉缓存让前端重新登录不要硬拿旧 key 去重试。最后说一个我自己的习惯每次新接这类开放数据接口我都先写一个最小脚本把解密链路单独测一遍传一组固定的 encryptedData、iv 和 session_key确认能解出预期明文再接到业务代码里。这样能把“接口没调通”和“业务逻辑有 bug”分开排查省掉很多互相甩锅的时间。希望这篇笔记能帮你在接微信运动步数时少踩几个坑把时间花在真正的业务功能上。本文还有配套的精品资源点击获取
返回列表