Angular 6 中为有效守卫引发的 NavigationCancel 事件
NavigationCancel event thrown for valid guards in Angular 6
我在导航到提供状态的过程中遇到 Angular 路由器问题。
我已经尝试使用带有 canLoad()
和 canActivate()
函数的自定义保护,但没有任何运气返回布尔值作为 true
。
Angular docs 声明如下:
NavigationCancel: An event triggered when navigation is canceled. This is due to a Route
Guard returning false during navigation.
因为我没有从路由器跟踪中获得更多调试信息(没有给出原因),我不得不在这里检查是否有修复,或者这是一个现有的错误。我也很感激在 Angular 6.
中有关调试路由器的其他方法的任何信息
控制台输出
我在 here 中创建了一个小项目。该项目需要访问提供者,我正在使用 angular-oauth2-oidc 存储库中提供的 OpenID Connect 提供者。 Password/username 是 max/geheim.
如何重现错误
- 克隆存储库并在 localhost:4200
提供站点
- 转到localhost:4200/oversikt/index
- 使用 max/geheim 作为 username/password
登录
- 读取控制台
更新
我怀疑这与导航到 children: []
路线有关。
我对你的代码做了一些调试,我发现这不是因为 links、auth guard、导航声明或模块配置,也不是 router beeing flakey in AG6,但这是因为..... 您使用的OAuth lib.
但让我解释一下。我发现正在发生以下情况:
- 您登录并被重定向回页面
- 您使用 link 返回应用程序,例如 /#YOUR AUT TOKEN
- 第一次导航已安排(id 1)
- 导航导致重定向到子页面 /oversikt
- 弹出导航2(重定向)
- 路由器以异步方式执行所有操作——它们是序列化的但仍然很难使用 RxJS——因此实际处理被延迟了——它已将当前导航 ID 作为参数传递(这很重要)
- 一些听众和其他订阅以及您正在使用的 OAUTH 库中的内容会触发
- 它 (lib) 检测到您的 url 中有令牌并删除它
- 这会触发另一个重定向 - 路由 ID 立即增加到 3
- 现在导航 2 继续并在某个时候(记住 JS 是单线程的)它检查(好吧 id 做了很多)导航开始时的导航 id 是否改变或仍然相同。
- 因为它有变化 - id 2 在计划时间传递,当前导航是 3,单个
false
在整个管道和路由器中的订阅中传播
- 将
boolean
(甚至不是 false,而是 bool)作为管道中的值会导致无故取消导航。
我将添加一些代码参考。但总的来说,这就是正在发生的事情。您的 oauth 库在导航期间修改 url 并导致它被取消。守卫们与直接的方式无关。
所以一般来说 - 它不会被取消,因为 "access is denied" 就像守卫的情况一样,但是它被取消是因为必须执行新的导航,所以它被取消短路了。
这里是(不是全部)相关代码:
OAuth 库修改
if (!this.oidc) {
this.eventsSubject.next(new OAuthSuccessEvent('token_received'));
if (this.clearHashAfterLogin && !options.preventClearHashAfterLogin) {
location.hash = '';
}
return Promise.resolve();
}
url 更改触发导航:
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);
});
}
};
导航 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); });
这是传递给路由器以启动的内容 "async" 路由 - id 是导航 id(之前递增)
Router.prototype.runNavigate = function (url, rawUrl, skipLocationChange, replaceUrl, id, precreatedState) {
此检查(在 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);
}
chain 中还有几个订阅,它们都有一些管道映射等以及已知的条件检查。
var preactivationResolveData$ = preactivationCheckGuards$.pipe(mergeMap(function (p) {
if (typeof p === 'boolean' || _this.navigationId !== id)
return of(false);
注意这是我之前写的,如果你在这里得到任何 booean,则 false 被向前推。因为我们这里已经有 false
因为在之前的管道映射中检查失败....
终于在链条的末端
if (typeof p === 'boolean' || !p.shouldActivate || id !== _this.navigationId || !p.state) {
// debugger;
navigationIsSuccessful = false;
return;
}
结果标志设置为 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);
}
NavigationCancel
没有您熟悉的任何消息(最后一个参数是消息 - 此处为空字符串):)。
我花了很多时间,因为我不知道 angular 内部结构 + 那些该死的管道......到处都是管道。
关于文档
NavigationCancel: An event triggered when navigation is canceled. This
is due to a Route Guard returning false during navigation.
好吧,他们忘了提到内部路由器可以取消导航,如果有导航队列正在建立:)
干杯!
我在导航到提供状态的过程中遇到 Angular 路由器问题。
我已经尝试使用带有 canLoad()
和 canActivate()
函数的自定义保护,但没有任何运气返回布尔值作为 true
。
Angular docs 声明如下:
NavigationCancel: An event triggered when navigation is canceled. This is due to a Route Guard returning false during navigation.
因为我没有从路由器跟踪中获得更多调试信息(没有给出原因),我不得不在这里检查是否有修复,或者这是一个现有的错误。我也很感激在 Angular 6.
中有关调试路由器的其他方法的任何信息控制台输出
我在 here 中创建了一个小项目。该项目需要访问提供者,我正在使用 angular-oauth2-oidc 存储库中提供的 OpenID Connect 提供者。 Password/username 是 max/geheim.
如何重现错误
- 克隆存储库并在 localhost:4200 提供站点
- 转到localhost:4200/oversikt/index
- 使用 max/geheim 作为 username/password 登录
- 读取控制台
更新
我怀疑这与导航到 children: []
路线有关。
我对你的代码做了一些调试,我发现这不是因为 links、auth guard、导航声明或模块配置,也不是 router beeing flakey in AG6,但这是因为..... 您使用的OAuth lib.
但让我解释一下。我发现正在发生以下情况:
- 您登录并被重定向回页面
- 您使用 link 返回应用程序,例如 /#YOUR AUT TOKEN
- 第一次导航已安排(id 1)
- 导航导致重定向到子页面 /oversikt
- 弹出导航2(重定向)
- 路由器以异步方式执行所有操作——它们是序列化的但仍然很难使用 RxJS——因此实际处理被延迟了——它已将当前导航 ID 作为参数传递(这很重要)
- 一些听众和其他订阅以及您正在使用的 OAUTH 库中的内容会触发
- 它 (lib) 检测到您的 url 中有令牌并删除它
- 这会触发另一个重定向 - 路由 ID 立即增加到 3
- 现在导航 2 继续并在某个时候(记住 JS 是单线程的)它检查(好吧 id 做了很多)导航开始时的导航 id 是否改变或仍然相同。
- 因为它有变化 - id 2 在计划时间传递,当前导航是 3,单个
false
在整个管道和路由器中的订阅中传播 - 将
boolean
(甚至不是 false,而是 bool)作为管道中的值会导致无故取消导航。
我将添加一些代码参考。但总的来说,这就是正在发生的事情。您的 oauth 库在导航期间修改 url 并导致它被取消。守卫们与直接的方式无关。
所以一般来说 - 它不会被取消,因为 "access is denied" 就像守卫的情况一样,但是它被取消是因为必须执行新的导航,所以它被取消短路了。
这里是(不是全部)相关代码:
OAuth 库修改
if (!this.oidc) {
this.eventsSubject.next(new OAuthSuccessEvent('token_received'));
if (this.clearHashAfterLogin && !options.preventClearHashAfterLogin) {
location.hash = '';
}
return Promise.resolve();
}
url 更改触发导航:
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);
});
}
};
导航 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); });
这是传递给路由器以启动的内容 "async" 路由 - id 是导航 id(之前递增)
Router.prototype.runNavigate = function (url, rawUrl, skipLocationChange, replaceUrl, id, precreatedState) {
此检查(在 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);
}
chain 中还有几个订阅,它们都有一些管道映射等以及已知的条件检查。
var preactivationResolveData$ = preactivationCheckGuards$.pipe(mergeMap(function (p) {
if (typeof p === 'boolean' || _this.navigationId !== id)
return of(false);
注意这是我之前写的,如果你在这里得到任何 booean,则 false 被向前推。因为我们这里已经有 false
因为在之前的管道映射中检查失败....
终于在链条的末端
if (typeof p === 'boolean' || !p.shouldActivate || id !== _this.navigationId || !p.state) {
// debugger;
navigationIsSuccessful = false;
return;
}
结果标志设置为 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);
}
NavigationCancel
没有您熟悉的任何消息(最后一个参数是消息 - 此处为空字符串):)。
我花了很多时间,因为我不知道 angular 内部结构 + 那些该死的管道......到处都是管道。
关于文档
NavigationCancel: An event triggered when navigation is canceled. This is due to a Route Guard returning false during navigation.
好吧,他们忘了提到内部路由器可以取消导航,如果有导航队列正在建立:)
干杯!