用户
 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,登录网站

小程序社区 首页 教程 实战教程 查看内容

微信小程序踩坑-Cookie登陆失败

Rolan 2020-12-2 14:21

本文的小程序应用是单独使用Cookie来维护登陆状态,登陆并未使用小程序的sessionKey来维护后台登陆状态。

1 问题描述

最近有用户反馈,小程序登陆有问题

小程序成功登陆后,安卓用户预约操作时,偶尔会出现登陆异常情况。

登陆失败现象极其诡异,问题难以复现。

1 用户10秒前刚登陆,用户后续操作马上提示“登陆异常”

2 部分安卓用户在登陆后,在后续操作提示“登陆异常”,这种现象是偶然发生的,安卓用户出现登陆异常概率大概是10分之1

2 苹果用户从未没有出现”登陆异常“现象。

 2 登陆实现方案

在介绍问题前,本文先简单描述下本文应用登陆实现方案。

本文的小程序应用是单独使用Cookie来维护登陆状态,登陆并未使用小程序的sessionKey来维护后台登陆状态。

后端Cookie校验用户登陆状态

为什么不使用小程序SessionKey维护登陆状态?

1 老应用有单独Cookie登陆方式。

2 后台支持多平台登陆(比如小程序、h5网页等),不完全依赖小程序SessionKey完成登陆 。

Shiro控制用户权限

1 获取微信小程序code值

2 code值以及appId换取用户openId

3 openId快捷登陆

4 小程序保存登陆Cookie

5 小程序携带Cookie请求后端应用

6 后端根据前端的Cookie校验用户的登陆情况

可惜小程序不支持Cookie,(浏览器一般会保存用户Cookie,方便后续浏览网页使用)

如何解决小程序支持Cookie登陆?

以下是网上常见的Cookie登陆解决方式。

  1. // 登录
  2. wx.login({
  3. success: function (res) {
  4. log.info(res)
  5. //获取登录的临时凭证
  6. var code = res.code;
  7. //调用后端,获取微信的session_key,secret
  8. wx.request({
  9. url: domain + '/user/wxLogin',
  10. header: {
  11. "Content-Type": "application/x-www-form-urlencoded"
  12. },
  13. method: "POST",
  14. data: util.json2Form({
  15. code: code,
  16. appId: that.globalData.appId
  17. }),
  18. success: function (result) {
  19. // cookie存储起来
  20. var cookie = result.header['Set-Cookie']
  21. wx.setStorageSync('cookie', cookie)
  22. },
  23. fail: function (res) {
  24. }
  25. })
  26. }
  27. })
  28. })

wx.request从res.header['Set-Cookie']中获取cookie信息,并使用wx.setStoargeSync将cookie信息同步写入小程序私有存储空间中

  1. wx.request({
  2. url: domain + '/api/xxx/xxx',
  3. header: {
  4. "Content-Type": "application/x-www-form-urlencoded",
  5. 'cookie': wx.getStorageSync("cookie")
  6. },
  7. method: 'POST',
  8. data: util.json2Form({ xx1: xx1, xx2: xx2 }),
  9. success: function (result) {
  10. },
  11. fail: function (res) {
  12. log.info("服务器异常:" + res)
  13. wx.showToast({
  14. title: '服务器异常',
  15. icon: 'none',
  16. duration: 2000
  17. })
  18. }
  19. })

wx.getStorageSync同步将cookie从小程序中取出,小程序携带该cookie请求后台服务,完成用户登陆状态校验。

 3、排查过程

问题不可怕,可怕的是不能稳定地复现case。本人平时使用iphone手机,重复用户的操作,基本复现不出来“登陆异常”的现象,只能在服务后台以及小程序前端疯狂埋点打日志。

1)后台日志排查,用户Cookie无效

从后台日志可以看出,用户成功登陆,但是用户没有在后续的请求使用用有效cookie去请求后台服务,后台直接拒绝服务。

2)微信小程序日志排查,安卓用户有问题

通过后台和小程序日志发现,出现“登陆异常”的用户基本是安卓用户,苹果用户基本没有这个问题。

 3)现象复现,安卓手机提示异常

目标锁定安卓手机,直接找了台安卓手机,重复登陆、预约操作,大概反复操作10次,终于复现了“登陆异常”的现象,喜大普奔啊。

 4)微信小程序埋点输出日志,Cookie存取正常

起初怀疑wx.setStoargeSync有bug,未将cookie成功写入小程序。

验证方式:将res.header['Set-Cookie']、wx.getStorageSync日志输出。

如果res.header['Set-Cookie']输出日志为空,则定位是后端服务问题,未将cookie携带返回。

如果res.header['Set-Cookie']输出日志不为空,wx.getStorageSync('cookie')输出日志为空,则定位setStorageSync写入有bug

但是最终现象res.header['Set-Cookie']、wx.getStorageSync('cookie')输出日志均不为空,排查思路中断了。

5)正常与异常Cookie对比,Cookie顺序不对

对比正常请求的cookie与异常请求的cookie

发现cookie的顺序不一样

后台shiro做权限控制,返回3个Set-Cookie值,苹果用户的请求基本是以JESSIONID开头,而有问题的安卓用户请求是以remeberMe=Delete开关

 6)异常Cookie排查,Cookie拼接不正确

将登陆异常请求的cookie按照正常请求cookie的顺序调整了下, 用户请求后端可以成功登陆。

使用错误顺序cookie请求后端,后端解析cookie并未获取到JESSIONID。

后端是如何解析Cookie,根据分号";"分割Cookie字符串,由于错误顺序Cookie是使用逗号做分割符,后端将Expires与JESSIONID视为一个整体,所以无法解析出JESSIONID

4、为什么苹果手机、部分安卓手机没有问题?

没有问题的Cookie,JESSIONID可以被后台正确分割出来。苹果手机获取Set-Cookie顺序是严格一致的,安卓手机Set-Cookie顺序是随机的。

 

5、问题原因

腾讯小程序Bug,Set-Cookie逗号拼接方式有问题

微信开放社区也有人反馈过这个bug,但是以微信社区人员解决问题的稀烂态度,至今未解决该bug。

解决bug只能靠自己去兼容这个bug

 

6、解决方法

当返回结果的header有多个Set-Cookier时,微信小程序获取res.header['Set-Cookie'],已经是将Set-Cookie用逗号拼接好的字符串。

如果使用简单的逗号分割,Expires时间也含有逗号,Cookie结果是错误的。

Cookie正则分割,分号重新拼接

见示例

简单的逗号无法分割,可以使用正则表达式去分割Cookie字符串,

需要被分割的逗号,后继字符串是含有=

 

7、标准答案

微信小程序使用Cookie登陆标准答案

  1. // 登录
  2. wx.login({
  3. success: function (res) {
  4. log.info(res)
  5. //获取登录的临时凭证
  6. var code = res.code;
  7. //调用后端,获取微信的session_key,secret
  8. wx.request({
  9. url: domain + '/user/wxLogin',
  10. header: {
  11. "Content-Type": "application/x-www-form-urlencoded"
  12. },
  13. method: "POST",
  14. data: util.json2Form({
  15. code: code,
  16. appId: that.globalData.appId
  17. }),
  18. success: function (result) {
  19. // Set-Cookie字符串获取
  20. var cookie = result.header['Set-Cookie']
  21. // 字符串分割成数组
  22. var cookieArray = cookie.split(/,(?=[^,]*=)/)
  23. // 分号拼接数组
  24. var newCookie = cookieArray.join(';')
  25. // 存储拼接后的cookie
  26. try {
  27. wx.setStorageSync('cookie', newCookie)
  28. } catch (error) {
  29. log.error('setStorageSync cookie fail')
  30. }
  31. },
  32. fail: function (res) {
  33. }
  34. })
  35. }
  36. })
鲜花
鲜花
鸡蛋
鸡蛋
分享至 : QQ空间
收藏