router.push()和location.reload()搭配产生的刷新问题

项目背景

一个后台管理系统,因为里面的内容由多个不同的项目组负责开发,于是领导要求将该系统重构成微前端。因该系统正在外部使用中,所以对微前端先进行用户试点,即登录使用的还是旧项目,在登录的时候识别该用户是否是微前端试点用户,是的话设置cookie的canary为‘always’,nginx会通过这个值去切换静态资源,而前端需要在登录成功后跳转到别的页面时使用location.reload()刷新去拿到最新的静态资源。


nginx配置

旧项目下登录后跳转的路由是/index/roomAudit。由于微前端划分了不同的子应用,菜单路由是后台配置的,所以路径先由前端写死了index替换,即微前端的路由会变成/operating/roomAudit(即这个路由对于旧项目来说是不存在的)。

问题

灰度方案(即使用canary去切换资源):会刷新login跳转后的页面(前提是项目跳不准确的路由不会报404)
微前端:会跳回login页面刷新


跳转后刷新

原因

使用灰度方案时,由于路由会由前端进行index替换成对应的子应用名字,所以router跳转的页面是不存在的;而单使用微前端时,路由名字已经是改成了对应的名字,对于项目来说router跳转的页面是存在的。那么问题可以转化为:

  1. router.push('不存在的页面A') -> location.reload()的页面效果为:跳转A,再刷新A页面
  2. router.push('存在的页面B') -> location.reload()的页面效果为:跳转B,再刷新login页面(原页面)
function resolveAsyncComponents (matched) {
  return function (to, from, next) {
    var hasAsync = false;
    var pending = 0;
    var error = null;

    flatMapComponents(matched, function (def, _, match, key) {
      // if it's a function and doesn't have cid attached,
      // assume it's an async component resolve function.
      // we are not using Vue's default async resolving mechanism because
      // we want to halt the navigation until the incoming component has been
      // resolved.
      if (typeof def === 'function' && def.cid === undefined) {
        hasAsync = true;
        pending++;

        var resolve = once(function (resolvedDef) {
          if (isESModule(resolvedDef)) {
            resolvedDef = resolvedDef.default;
          }
          // save resolved on async factory in case it's used elsewhere
          def.resolved = typeof resolvedDef === 'function'
            ? resolvedDef
            : _Vue.extend(resolvedDef);
          match.components[key] = resolvedDef;
          pending--;
          if (pending <= 0) {
            next();
          }
        });

        var reject = once(function (reason) {
          var msg = "Failed to resolve async component " + key + ": " + reason;
          "development" !== 'production' && warn(false, msg);
          if (!error) {
            error = isError(reason)
              ? reason
              : new Error(msg);
            next(error);
          }
        });

        var res;
        try {
          res = def(resolve, reject);
        } catch (e) {
          reject(e);
        }
        if (res) {
          if (typeof res.then === 'function') {
            res.then(resolve, reject);
          } else {
            // new syntax in Vue 2.3
            var comp = res.component;
            if (comp && typeof comp.then === 'function') {
              comp.then(resolve, reject);
            }
          }
        }
      }
    });

    if (!hasAsync) { next(); }
  }
}

通过查看vue-router源码发现,当要跳转的路由是不存在的情况下,hasAsync为false,直接next(),相当于是同步的,因此是先跳转路由再刷新页面,刷的就是跳转后的路由。当要跳转的路由是存在的情况下,会进入到resolve函数里,是异步的,就会先刷新而此时路由跳转过程还没有完成,就会导致刷新的是跳转前的页面。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容