本文目录8 节

一个顺手判断,埋下了状态错位

付费页面可以从多个位置打开。为了让页面知道应该先展示哪块内容,入口会携带一个简单参数。

这个参数最初只负责界面定位,后来却被顺手拿来判断用户有没有有效权益:某个入口默认按未开通处理,另一个入口默认按已开通处理。

在单一路径里,它看起来没有问题。一旦用户身份、数据刷新时机和进入页面的方式没有刚好对上,页面就会出现矛盾:用户的真实权益没有变化,界面却因为入口不同给出了不同答案。

这次排查让我先改掉了一个错误前提:路由记录的是用户怎样来到这里,不是用户拥有什么。

入口意图和业务事实不是同一种状态

路由参数适合表达一次性的导航意图,例如:

  • 从哪个页面进入;
  • 希望优先看到哪个区域;
  • 是否需要在加载完成后执行一次界面动作。

权益状态回答的是另一组问题:

  • 当前账号是否已经登录;
  • 服务端是否确认权益有效;
  • 本地拿到的数据是否仍在有效期内;
  • 最近一次交易结果是否已经完成校验。

两者的生命周期也不同。导航意图通常在页面打开后就可以消费,权益状态却可能在登录、交易、恢复购买或重新拉取账号信息后变化。

如果把短期入口参数当成长期业务事实,页面第一次打开也许正确,之后的刷新、回退和账号切换都会留下隐患。

三种路径足以暴露问题

我用三条简单路径检查原来的判断:

  1. 用户直接打开页面,没有携带任何入口参数;
  2. 已有有效权益的用户从普通提示入口进入;
  3. 用户停留在页面期间,权益状态完成刷新,但路由没有变化。

原逻辑在这些路径中会得到不一致的界面状态。问题不在某个按钮,而在状态来源选错了。

因此,后续修复没有继续增加入口分支,而是先确定唯一的权威来源:页面只能根据已经校验的账号权益决定业务状态。入口参数仍然保留,但只负责界面落点。

页面需要允许“暂时不知道”

权益请求是异步的。页面刚挂载时,前端可能还没有答案。

如果只使用一个布尔值,false 很容易同时表示:

  • 已确认没有有效权益;
  • 请求尚未开始;
  • 请求仍在进行;
  • 请求失败,暂时无法确认。

这些情况在界面上不应该得到同一种结果。我把状态拆成了更明确的阶段:

UNKNOWN
  -> LOADING
  -> ACTIVE | INACTIVE | ERROR

UNKNOWNLOADING 期间,页面保持中性加载状态;只有拿到有效响应后,才进入 ACTIVEINACTIVE。请求失败则显示可重试状态,而不是猜一个看似安全的默认值。

这一步避免了页面在网络较慢时先闪出错误内容,也避免把“查询失败”误写成“用户没有权益”。

先确认事实,再消费入口意图

调整后的页面初始化顺序变成:

进入页面
  -> 读取导航意图
  -> 查询当前账号权益
  -> 根据权威结果确定业务状态
  -> 在允许的范围内应用导航意图

可以把最后一步理解成一个小的选择函数:

selectInitialView({ entitlement, intent })

它只做几件事:

  • 已确认的权益结果优先;
  • 导航意图只能选择当前用户可以访问的界面;
  • 缺少入口参数时使用稳定的默认页面;
  • 权益刷新后重新计算,而不是沿用旧入口留下的结果。

这样处理后,入口仍然可以改善体验,却没有权限修改业务事实。

交易回调也不能直接充当最终权益

类似的混用还会出现在交易完成之后。

客户端收到成功回调,能证明某一步交易流程已经完成,但它不一定等于账号权益已经刷新。网络延迟、服务端校验和跨设备同步都可能让两者短暂错开。

更稳妥的链路是:

客户端收到结果
  -> 请求服务端校验或刷新账号状态
  -> 获取新的权益数据
  -> 更新页面

客户端回调负责触发刷新,服务端确认的数据负责决定最终界面。这样即使页面被关闭后重新打开,也不会依赖上一次组件留下的临时变量。

验证时不要只点一条入口

这类问题很容易在单一路径中“看起来已经修好”。我的回归清单至少覆盖:

  • 无入口参数时直接打开;
  • 从不同页面进入同一付费页;
  • 请求较慢和请求失败;
  • 页面停留期间重新拉取权益;
  • 交易完成后刷新账号状态;
  • 退出登录或切换账号后重新进入。

纯状态选择可以用测试固定输入输出,路由与页面表现需要浏览器回归,真实交易和账号同步则要在对应环境中继续确认。

这几个层次不能互相代替。构建通过只能说明代码可以打包,模拟回调也不能证明真实账号已经获得权益。

这次修复留下的判断

以后再看到 sourceactionfrom 一类入口字段,我会先问它究竟是命令还是事实。

如果它只说明“这次从哪里进入”或“希望页面做什么”,就不应该参与长期业务状态判断。账号权益、权限和交易结果都需要稳定、可刷新并且能够在页面重建后重新取得的权威来源。

入口参数可以影响体验,但不能替用户身份和真实权益作决定。

Recommended

继续阅读

  1. 修复 Bug 之后,怎样真正吃透相关代码工程笔记 · 7 分钟
  2. 一个一直显示“生成中”的任务,为什么不能直接重新提交工程笔记 · 8 分钟