非相同请求被canceled的bug排查

BUG描述
  在工单的详情页有一个跳转到设备管理的按钮(到设备页后网页会发起两个请求——一个是detail,一个是dev),一开始这个detail会报错———无效的输入,这个时候dev接口还是可以正常请求的。结果后台把detail接口报错修复之后,发现dev接口一直是被canceled的状态。一开始还以为是后台的问题,因为我们封装的请求里面是网页发起两个相同的请求时,如果前一个请求没有返回时,网页继续发起相同的请求,代码里默认是就会把前一个请求abort。直到后面后台一直说他后台没有报错,这时我调试控制台,将网速降到slow 3G之后,发现dev请求不被canceled,这时候才把问题定位在前端。其实把请求给canceled的操作只能是前端操作的,后端设置接口时只能设置成超时。我不应该一开始就把后台拉下来定位问题的。。。

排查问题
  定位到前端问题后,我发现sf-table里面有一个v-if,我以为是v-if为false时把sf-table给隐藏了,导致发起的请求也被终止了,但是后面一想,模板的渲染跟请求没有啥关系,要排查问题,还是得从util/request中开始排查。

定位问题
  开始打断点,发现只要接口被canceled的时候,就会进入abortAll这个函数,于是全局搜索abortAll,发现Router.beforeEach中会去调用这个函数,这时才定位到原来dev被canceled是因为detail请求之后,路由发生了改变,此时查看detail的成功回调中,果然有操作路由的动作———router.push({query:{role:data.phase}});

问题剖析
  因为这个detail的请求是放在vuex的action里面去做的,每次只要客户管理的模块被加载,这个action就会在mounted里被触发,而之前要解决的bug是在客户管理的客户信息下面才有这个问题,现在如果把这个改变路由的代码放在客户信息下去做,就不会有这个问题了,因为客户信息本来也只有调用detail这个接口。所以最终的解决方案就是把这个router.push({query:{role:data.phase}})放在客户信息的路由下去做(监听路由,路由中包含info时,才在调用action中把操作路由的回调给传入,在detail请求成功的回调中执行)。

问题回顾
  此时查看代码提交记录,发现该代码是要解决一个td而添加的,这个td是用户打开了两个页面,在一个页面中去修改某个客户的服务项,但是在另外一个页面却没有更新客户管理模块中的客户信息的服务项,原因就是没有去加载detail的这个接口,于是mc之前改td的时候就是用watch,在路由中包含info的时候,就会去调用detial的接口,然后去更新路由的查询中的role。这样之后查询会把最新的role给带过去,写到这里我才发现,从表格进去的时候,用户可能有(3、5)这两种角色,在另外的网页中,用户可以把对应的(3、5)升级成(6、7),此时后台应该直接把前端请求的3映射成6,把请求的5映射成7,而不应该都依赖于前端去修改请求参数。要不然前端来做这种操作一般都会引发其他的问题。因为同一个页面,可能会有多个入口,没有办法保证每个入口都会给这个页面传一个role值,比如一开始的detail接口中报错———无效的参数,就是因为在详情中跳转过来没有带一个role值过来,请求的时候detail就直接报错了,这个的解决方法是后端判断role这个参数没有传值时,做了兼容的处理,同理我觉得客户信息页没有刷新也是同样的问题。
  因此,涉及到这种过于依赖前端查询参数的接口的,要尽可能让后端做映射、兼容处理。

  注意 之后遇到类似的交互场景、依靠前端这种添加路由的形式去做的要额外小心,因为后续一旦修改了路由参数的,可能又会发生类似的问题,特别是在整个大模块(下面可能会对应多个路由)mounted的时候就执行的场景。