在Angular 6中为有效警卫抛出NavigationCancel事件

Gje*_*t G 6 angular angular-router angular-guards

我在导航到提供状态的过程中遇到了Angular路由器的问题.

我试过使用自定义后卫canLoad()canActivate()功能返回布尔值true没有任何运气.

Angular 文档声明如下:

NavigationCancel:取消导航时触发的事件.这是由于Route Guard在导航期间返回false.

由于我没有从路由器跟踪中获得更多调试信息(没有给出任何理由),我被迫在这里检查是否存在修复,或者这是否是现有错误.我也很欣赏有关在Angular 6中调试路由器的其他方法的任何信息.

控制台输出

控制台输出

我在这里创建了一个小项目.该项目需要访问提供者,我正在使用angular-oauth2-oidc存储库中提供的提供的OpenID Connect提供程序.密码/用户名是max/geheim.

如何重现错误

  1. 克隆仓库并在localhost:4200上提供网站服务
  2. 转到localhost:4200/oversikt/index
  3. 以max/geheim身份登录为用户名/密码
  4. 阅读控制台

更新 我怀疑它与导航到children: []路线有关.

Ant*_*sss 12

我在你的代码中进行了一些调试,我发现这不是因为链接,auth后卫,导航声明或模块配置,也不是AG6中的路由器,但它是因为..... OAuth lib you正在使用.

但让我解释一下.我发现以下情况正在发生:

  1. 您登录并重定向到页面
  2. 您可以使用/ #YOUR AUT TOKEN等链接返回应用程序
  3. 安排第一次导航(标识1)
  4. 导航导致重定向到子页面/ overikt
  5. 导航2弹出(重定向)
  6. 路由器以异步方式执行所有操作 - 它们是序列化的但是sxluses RxJS很难 - 因此实际处理被延迟 - 它已经将当前导航id作为参数传递(这很重要)
  7. 某些侦听器和其他订阅以及您正在使用的OAUTH lib中的内容都会触发
  8. 它(lib)检测到您的URL中有令牌并删除它
  9. 这会触发另一个重定向 - 路由ID为INCREMENTED RIGHT AWAY为3
  10. 现在导航2继续并且在某些时候(记住JS是单线程的)它检查(如果导航开头的导航id改变或仍然相同,那么很好地做了很多).
  11. 由于它有变化 - 在计划时间传递了id 2,并且当前导航为3,false因此在整个管道中传播单个并在路由器中进行订阅
  12. boolean(甚至是假的,但是bool)作为管道中的值导致CANCEL导航没有任何理由.

我添加了一些代码参考.但总的来说,这就是发生的事情.你的oauth lib在导航过程中修改url并导致它被取消.卫兵与此直截了当地没有任何关系.

所以一般情况下 - 它没有被取消,因为"访问被拒绝",就像警卫一样,但它被取消,因为必须执行新的导航,所以它被取消短路.

这是(不是全部)相关代码:

OAuth lib修改

   if (!this.oidc) {
            this.eventsSubject.next(new OAuthSuccessEvent('token_received'));
            if (this.clearHashAfterLogin && !options.preventClearHashAfterLogin) {
                location.hash = '';
            }
            return Promise.resolve();
        }
Run Code Online (Sandbox Code Playgroud)

网址上的导航触发更改:

 Router.prototype.setUpLocationChangeListener = function () {
        var _this = this;
        // Don't need to use Zone.wrap any more, because zone.js
        // already patch onPopState, so location change callback will
        // run into ngZone
        if (!this.locationSubscription) {
            this.locationSubscription = this.location.subscribe(function (change) {
                var rawUrlTree = _this.parseUrl(change['url']);
                var source = change['type'] === 'popstate' ? 'popstate' : 'hashchange';
                if(this.rou)
                var state = change.state && change.state.navigationId ?
                    { navigationId: change.state.navigationId } :
                    null;
                setTimeout(function () { console.error("FROM LOCATION SUB");_this.scheduleNavigation(rawUrlTree, source, state, { replaceUrl: true }); }, 0);
            });
        }
    };
Run Code Online (Sandbox Code Playgroud)

导航ID修改 - 立即发生:

   var id = ++this.navigationId;
    console.error("ANOTHER SCHEDULED LOL LOL LOL!!!");
    this.navigations.next({ id: id, source: source, state: state, rawUrl: rawUrl, extras: extras, resolve: resolve, reject: reject, promise: promise });
    // Make sure that the error is propagated even though `processNavigations` catch
    // handler does not rethrow
    return promise.catch(function (e) { return Promise.reject(e); });
Run Code Online (Sandbox Code Playgroud)

这是传递给路由器以启动"异步"路由的内容 - id是nav id(先前增加)

 Router.prototype.runNavigate = function (url, rawUrl, skipLocationChange, replaceUrl, id, precreatedState) {
Run Code Online (Sandbox Code Playgroud)

这个检查(在runNav中)首先因为id改变而失败,所以2!== 3 - FALSE被返回到管道

var preactivationCheckGuards$ = preactivationSetup$.pipe(mergeMap(function (p) {
            if (typeof p === 'boolean' || _this.navigationId !== id) //NAVIGATION ID CHANGES HERE!
            {
              console.warn("PREACTIVATE GUARD CHECK ");
              console.log(p);
              // debugger;
              return of(false);
            }
Run Code Online (Sandbox Code Playgroud)

在chaing中还有几个订阅,它们都有一些管道映射等以及已知的条件检查.

 var preactivationResolveData$ = preactivationCheckGuards$.pipe(mergeMap(function (p) {
                if (typeof p === 'boolean' || _this.navigationId !== id)
                    return of(false);
Run Code Online (Sandbox Code Playgroud)

请注意,这是我之前写的,如果你在这里得到任何booean,那么就会向前推进false.因为我们已经false在这里因为先前的管道图中的检查失败了....

最后在链的末尾

    if (typeof p === 'boolean' || !p.shouldActivate || id !== _this.navigationId || !p.state) {
      // debugger;
        navigationIsSuccessful = false;
        return;
    }
Run Code Online (Sandbox Code Playgroud)

结果标志设置为false,这会导致

 .then(function () {
        if (navigationIsSuccessful) {
            _this.navigated = true;
            _this.lastSuccessfulId = id;
            _this.events
                .next(new NavigationEnd(id, _this.serializeUrl(url), _this.serializeUrl(_this.currentUrlTree)));
            resolvePromise(true);
        }
        else {
            _this.resetUrlToCurrentUrlTree();
            _this.events
                .next(new NavigationCancel(id, _this.serializeUrl(url), ''));
            resolvePromise(false);
        }
Run Code Online (Sandbox Code Playgroud)

NavigationCancel 没有任何消息(最后一个参数是消息 - 这里的emtpy字符串),你知道的很好:).

我花了很多钱,因为我不知道有角度的内部结构+那些血腥的管道......到处都是管道.

至于文档

NavigationCancel:取消导航时触发的事件.这是由于Route Guard在导航期间返回false.

好吧,他们忘了提到内部路由器可以取消导航是有队列的导航建立:)

干杯!