我如何 return true/false 基于 api 响应消息在我的 angular authguard 方法中?

How can I return true/false based on api response message in my angular authguard method?

我已经放置了一个 angular 路由验证器来放置我的页面。我有一个 api 检查令牌是否有效,并基于此我想 return true 或 false 以进行进一步导航。

但似乎在 'subscribe' 中我分配了我的 'result' 标志 true 而不是在订阅之外持续存在。 'result' 变量在错误的范围内吗?我该如何纠正?请帮助我理解我在下面代码中的错误。

canActivate( next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
  const jwt = localStorage.getItem('jwt');
  let result = false;

  this.signinService.isSignedin(jwt).subscribe((res) => { // <---
    console.log(res.json().message);
    if (res.json().message === 'Token Valid') {
      result = true;
      console.log(result);
      return true;
    } else {
      result = false;
      return false;
    }
  }, (err) => { // <---
    console.log(err);
    result = false;
    return false;
  });
  console.log('END' + result);
  return result;}

上面的代码按以下顺序打印在控制台上,这对我来说似乎很奇怪。请问有人可以解释一下吗?

ENDfalse

令牌有效

正确

结果值在您定义的回调函数执行前返回。这是非常合乎逻辑的,因为回调是在 api 往返完成后调用的。

But seems that in 'subscribe' I assign my 'result' flag true not persisting outside of the subscribe.

我认为您没有完全理解解释器将如何阅读和评估这段代码。因为 JavaScript event loop 从不阻塞 ,解释器将到达订阅块,发出请求,并且然后继续执行订阅块之外的代码,而不等待响应返回。这就是为什么首先打印 "ENDfalse" 的原因。然后响应进来并执行回调函数,行 console.log(res.json().message); 打印 "Token Valid" 和 console.log(result); return 正确。

解决此问题的一种方法可能是 return 整个可观察对象,然后在您实际想要使用 "result" 值的地方订阅(实际上是您的函数签名canActivate 表明你应该 returning 一个 observable,而不是数据)。

canActivate( next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
  const jwt = localStorage.getItem('jwt');
  return this.signinService.isSignedin(jwt);
}

你不能 return 来自 subscribe 的任何东西,但你可以做的是 return 从你的守卫那里得到一个 Observable。

也正如其他人所指出的,这是异步的,因此是控制台日志的顺序。您可以在这里阅读更多相关信息:

至于如何格式化你的代码,让我们如前所述return一个Observable:

// add 'return' and use 'map' instead: 
return this.signinService.isSignedin(jwt).map((res) => {
  if (res.json().message === 'Token Valid') {
    return true;
  } else {
    return false;
  }
}, (err) => {
  return false;
});