kita / notes

约 2 分钟

别人绑定了账号,查出来的还是我的战绩

给王者荣耀查分插件加了绑定功能:群里每个人绑一次自己的营地账号,之后发指令就查自己的,不用每次输 ID。

按 QQ 号绑,逻辑上各绑各的。测的时候是两个人各绑一个账号,然后各自查。

第二个人查出来的,是我的战绩。

换错账号也一样

第一次发现的时候我以为是绑定没生效——第二个人绑的时候可能写失败了,所以回落到某个默认账号。

那就换个更极端的测法:用一个明显错误的营地账号去绑。如果绑定确实生效了,接口应该报"找不到这个账号"之类的错。

结果是:照旧返回我的信息。

这一步把范围缩小了很多。说明它根本没在看当前用户绑了什么,而是永远用同一个数据源。绑定这个动作可能执行了、写进存储了,但查询那一侧压根没读它。

这类 bug 的通病

多用户场景下,凡是"全局"的东西,都是 bug 的候选。常见的三种:

一是模块级的单例状态。 插件初始化的时候把「当前用户的营地 ID」存成一个成员变量,第一个用户的请求把它填上,之后所有用户都读这个值。请求之间没有隔离。

二是缓存 key 没带用户标识。 缓存本身没问题,但 key 写成 gok:profile 这种全局名字,第一个用户把数据写进去,第二个用户查的时候直接命中缓存——返回值看着完全正常,就是不是他的。

三是默认值兜底兜错了。 配置里留了个默认账号(比如开发者自己测试用的),查询时"取不到用户的绑定就回落到默认",而这个"取不到"的判断写错了,于是永远走默认分支。

我那次的具体原因记不太清了,但排查路径是这样:先确认绑定数据写进去了没有(看存储),再确认查询时读了没有(在查询入口打日志)。这两步能立刻分开"写的问题"和"读的问题"。

顺带暴露的另一件事

同一批测试里还发现,这个插件的绑定状态和别的模块有耦合——有一次改了别的地方,绑定也跟着失效了。

这提醒我:多用户的状态隔离要单独测。开发时自己一个人测,永远测不出来——你绑自己的号、查自己的号,全程只有一个用户,全局变量和局部变量表现一样。必须两个人测,或者手动伪造第二个用户身份。

现在的做法是:任何涉及"每个用户不一样"的功能,上线前都用一个假身份走一遍。这个成本很低,但能挡住一整类问题。

← 回到全部笔记