微信公众号 - Code失效的真相!

1,677 阅读4分钟

您在读这篇文章之前,我想对您说一句话:

如果说雪崩之时,没有任何一片雪花是无辜的

那么相对于程序中的BUG也是一样的

疯狂报错之时,没有任何一个字母是无辜的

今天一大早刚到公司,一个自己之前开发的运行平稳的微信公众号出现了一个莫名奇妙的BUG,抛出错误信息:未定义的索引openid!!!

出现问题之后立刻做出反应,找到对应代码报错行数,从上到下走一遍业务逻辑的处理。

先多余地赘述一下微信公众号网页授权获取用户信息的步骤:

  1. 用户同意授权,获取Code
  2. 通过code换取网页授权access_token
  3. 刷新access_token(如果需要)
  4. 拉取用户信息(需scope为 snsapi_userinfo)

我使用的是scope为snsapi_userinfo的方式(之前在这儿也有一个小坑,不过解决方式文档有详细说明了,其实就是在已经关注公众号的情况下,在公众号中做主动授权想拉取授权页的时候也都是通过静默授权用户无感知的情况下授权的,而在PC端登陆微信后,再次进入公众号进行页面跳转时则会出现授权页面)

经过对自己程序的排查,基本排除了代码编写错误或者使用未定义的变量,于是去找文档,跟着上面的步骤,又排查了一遍自己获取授权,拉取用户信息的代码,也没有任何问题那问题究竟出现在哪里了呢?

仔细想过不难发现,其实问题就在眼前,倒推一下就知道,要想拿到用户信息(openid,headimgurl),就要acess_token(此处acess_token不同于基础支持中的acess_token),而获取acess_token就要拿Code换取,要想拿到Code就需要用户走过授权链接

https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxf0e81c3bee622d60&redirect_uri=http%3A%2F%2Fnba.bluewebgame.com%2Foauth_response.php&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect

到此为止,一个用户通过手机访问微信公众号的一个流程就走完了获取信息之后,就走正常的业务逻辑了,于是一步一步试吧,通过Charles抓包手机的请求,发现手机无论如何授权或者无论怎么请求,取消关注、关注等等任何操作,捣鼓了一阵儿没有任何报错!

此时已经到了崩溃的边缘,线上频繁报错,压力顶不住啦!然后开始求助度娘,也给出了一些解决办法,但是我认为那不是问题的根本原因,直到看到CSDN上一语道破天机:“手机用户无论怎么访问都不会出现Code失效问题!”难道还有人在PC端登陆微信,然后在公众号中的微信浏览器中操作?

带着这个疑问,我登陆了自己微信在公众号中开始了自己的测试,下面我把自己的操作步骤告诉大家(仅限于PC端微信公众号操作):

  1. 进入公众号随便点击一个菜单或者弹出的消息引导用户授权,拉起的授权页面出现

  1. 授权成功之后进入个人中心

  1. 此时注意了,如果你想报错请不停点击微信浏览器为您精心准备的后退按钮,报错之前呢你会看到这样一个提示的页面

  1. 然后静静等待几秒钟(根据网速而定),你的程序会收到一个报错信息,总之是关于openid的问题

通过对以上的操作抓包分析,发现PC端操作的点击后退后会重新用一次你之前获取的Code去拉取你的用户信息(顺便说一下看到一个对于此问题百度到的结果,大致意思其实是可能浏览器中的后退使用的Location.replace()),而此时的Code其实第一次你已经用过的Code了,这个换取信息的Code只能用一次,用过了就失效了。

说到这儿,剩下的就不说了,因为我觉得我解决问题的方式比较LOW,虽然问题得到解决,但总觉得不是根本上的,因为我只是在项目中加了这样一个页面,如果发现通过Code获取access_token的时候返回了error_code,我就去跳转一个类似于404的页面,提供一个重新授权的按钮,可供跳转。

一个不算总结的总结

  1. 解决这个问题的时候又犯了老毛病,起初我只着眼于自己的变量是否定义的问题,并没有去想它的来龙去脉,追根朔源。
  2. 我再一次被表象给蒙蔽了,难道微信是手机上一个非常好用的APP我就默认排除了可能在PC上操作的可能了吗?
  3. 解决问题的时候或者写代码遇到问题的时候,我觉得最好你还是让一个你的伙伴也来看看这个问题,有的时候你可能真的没在意细节,或者说你没注意到的角落,当你没有注意到的时候,一个字母都能让你的程序报错