1. 旧版基础库获取手机号的背景与挑战在微信小程序开发中获取用户手机号一直是个高频需求场景。对于基础库2.21.2之前的版本整个流程需要开发者自己处理加密数据解密这对很多新手来说是个不小的挑战。我最早接触这个功能时就曾被session_key的有效期问题坑过好几次。与新版接口最大的不同在于旧版方案需要开发者自行实现解密逻辑。前端通过button组件触发获取加密数据后必须将encryptedData、iv等关键参数传给服务端再用session_key进行AES解密。整个过程涉及多个技术要点wx.login获取的code有效期仅5分钟但用户可能不会立即点击获取手机号按钮session_key需要缓存但不可泄露否则会导致用户数据被非法解密解密失败率高达30%主要由于参数传递错误或加密算法实现偏差实际项目中我发现很多开发者卡在Java解密环节最常见的就是PKCS7Padding的兼容性问题。微信官方文档对这部分描述比较简略需要反复调试才能掌握要领。2. 前端实现关键步骤详解2.1 WXML按钮配置要点旧版接口必须使用特定格式的button组件button open-typegetPhoneNumber bindgetphonenumbergetPhoneHandler classcustom-btn 获取手机号 /button三个关键属性缺一不可open-type必须设置为getPhoneNumberbindgetphonenumber指定回调函数名type建议用default而非primary避免被误认为主操作我遇到过按钮点击无响应的情况最后发现是漏写了bindgetphonenumber属性。调试时可以先用console.log打印事件对象确认是否正常触发。2.2 JS逻辑处理实战核心代码结构如下let tempCode // 临时存储login返回的code Page({ onLoad() { this.getLoginCode() }, getLoginCode() { wx.login({ success: (res) { if (res.code) { tempCode res.code // 注意有效期只有5分钟! } } }) }, getPhoneHandler(e) { if (!tempCode) { return wx.showToast({ title: 请重新登录 }) } wx.request({ url: https://your.domain.com/api/decrypt, method: POST, data: { code: tempCode, encryptedData: e.detail.encryptedData, iv: e.detail.iv, appId: 你的小程序appid }, success: (res) { console.log(解密结果:, res.data) } }) } })容易踩的坑code过早获取导致过期建议在onShow或按钮点击时现取未处理用户拒绝授权的情况e.detail.errMsg包含错误信息传参时字段名拼写错误比如encryptData少个ed3. 服务端解密全流程解析3.1 Java解密核心代码实现解密工具类需要包含以下关键方法public class WxDecryptUtil { private static final String AES_CBC_PADDING AES/CBC/PKCS7Padding; public static String decryptPhone( String encryptedData, String sessionKey, String iv) throws Exception { byte[] dataBytes Base64.getDecoder().decode(encryptedData); byte[] keyBytes Base64.getDecoder().decode(sessionKey); byte[] ivBytes Base64.getDecoder().decode(iv); SecretKeySpec keySpec new SecretKeySpec(keyBytes, AES); IvParameterSpec ivSpec new IvParameterSpec(ivBytes); Cipher cipher Cipher.getInstance(AES_CBC_PADDING); cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); byte[] result cipher.doFinal(dataBytes); return new String(result, StandardCharsets.UTF_8); } }参数验证要点检查watermark中的appId是否匹配验证session_key是否过期建议缓存2小时encryptedData长度必须大于24位3.2 完整接口处理流程Controller层典型实现PostMapping(/decrypt/phone) public Result decryptPhone( RequestBody DecryptRequest request) { // 1. 校验基础参数 if (StringUtils.isEmpty(request.getCode())) { return Result.fail(code不能为空); } // 2. 获取session_key String url String.format( https://api.weixin.qq.com/sns/jscode2session?appid%ssecret%sjs_code%s, request.getAppId(), appConfig.getSecret(), request.getCode()); String response HttpUtil.get(url); JSONObject json JSON.parseObject(response); String sessionKey json.getString(session_key); // 3. 执行解密 try { String result WxDecryptUtil.decryptPhone( request.getEncryptedData(), sessionKey, request.getIv()); JSONObject data JSON.parseObject(result); return Result.success(data.getString(phoneNumber)); } catch (Exception e) { log.error(解密失败, e); return Result.fail(解密失败); } }4. 高频问题排查指南4.1 常见错误代码对照表错误现象可能原因解决方案illegal bufferiv参数错误检查Base64解码是否正确invalid appid缓存了错误的session_key重新获取code和session_keydecrypt error加密数据被篡改检查网络传输是否完整40029code无效检查code是否过期或重复使用4.2 调试技巧分享使用微信开发者工具模拟器在编译模式中选择获取手机号场景可以模拟不同授权结果服务端日志记录log.info(iv长度: {}, iv.length()); log.info(sessionKey长度: {}, sessionKey.length()); log.info(encryptedData前10位: {}, encryptedData.substring(0,10));Postman测试解密 先通过/auth接口获取有效的session_key再用以下参数测试{ encryptedData: 从客户端获取的真实数据, iv: 从客户端获取的iv, sessionKey: 从code2session获取 }我在处理一个企业项目时曾遇到iOS设备解密失败但Android正常的情况。最终发现是Base64编码的换行符处理不一致导致的。建议服务端统一使用Base64.getDecoder()这种JDK标准库方法。