【问题标题】:Delays with angular universal and ngIf checks - Angular 9角度通用和 ngIf 检查的延迟 - Angular 9
【发布时间】:2020-07-18 16:34:30
【问题描述】:

我刚刚开始在现有的应用程序中集成 Angular Universal,我注意到页面呈现错误的布局并且当页面完全加载时一切看起来都很好。

这是一个例子:

我在页面加载时得到这样的登录状态:

this.authService.isLoggedIn.subscribe(res => {
  this.isLoggedIn = res;
});

并根据结果为真或假设置不同的布局:

<div *ngIf="isLoggedIn" class="user-logged">
    // user logged in
</div>
<div *ngIf="!isLoggedIn" class="user-logged">
    // user not logged in
</div>

但是当服务返回 true(这意味着用户已登录)时,我可以看到未登录状态,然后页面加载,一切看起来都很好。 所有 BreakpointObserver 检查也会发生这种情况。

更新 1: 这是我尝试过的: 我创建了一个 AppConfigService:

@Injectable()
export class AppConfigService {

  private isLoggedStatus: boolean;

  constructor(private authService: AuthService) { }

  public isLoggedIn(): boolean {
    return this.isLoggedStatus;
  }

  load() {
    return new Promise((resolve, reject) => {
      this.authService.isLoggedIn.subscribe(loggedInStatus => {
        this.isLoggedStatus = loggedInStatus;
        resolve(true);
      });
    });
  }

}

在我的 AuthService 中:

private isLoginSubject = new BehaviorSubject<boolean>(this.isAuthenticated);

get isLoggedIn(): Observable<boolean> {
    return this.isLoginSubject.asObservable();
}

get isAuthenticated(): boolean {
    const token = this.getToken();
    if (token) {
      if (jwtHelper.isTokenExpired(token)) {
        return false;
      } else {
        return true;
      }
    } else {
      return false;
    }
}

在我的 app.module.ts 中

export function appConfigFactory(provider: AppConfigService) {
  return () => provider.load();
}

providers: [
    AppConfigService,
    {
        provide: APP_INITIALIZER,
        useFactory: appConfigFactory,
        deps: [AppConfigService],
        multi: true
    }
]

我认为问题在于服务器端使用本地存储,但如果这是问题,我如何检查用户是否已登录?

【问题讨论】:

    标签: angular angular-universal


    【解决方案1】:

    发生这种情况是因为,当您的应用首次评估 isLoggedIn 时,它是 false(或未定义,这取决于您如何定义它)。

    然后,当 subscribe 事件返回数据时,isLoggedIn 值会发生变化,因此您的 html 也会因为您的 *ngIf 条件而发生变化。

    如果你想在应用渲染之前加载isLoggedIn数据,你可以使用APP_INITIALIZER

    这篇文章解释了如何使用它:https://www.cidean.com/blog/2019/initialize-data-before-angular-app-starts/

    这个比较老但是也不错:https://devblog.dymel.pl/2017/10/17/angular-preload/

    编辑

    在你的AppConfigService 中,isLoggedStatus 应该是一个 Observable,否则在 Promise 解决之前它将是未定义的(并评估为 false)。

    你应该等到 promise 结束来渲染你的组件。

    示例步骤:

    • 显示登录页面。
    • 当用户点击登录时,调用您的服务器并等待响应。
    • 如果成功:
      • isLoggedStatus =
      • 保存会话(如果需要,可以在 LocalStorage 中)
      • 显示您的组件(isLoggedIn 为真)
    • 如果失败:
      • isLoggedStatus = 错误
      • 显示你的组件(isLoggedIn 会是假的)
      • 用户应该有机会重试登录

    【讨论】:

    • 我刚刚试过了,还是不行。通过来自 AppConfigService 的 isLoggedIn 响应的 console.log(),我得到了两个不同的结果。在浏览器控制台中,我得到了一个真值,而在 ssr 服务器控制台中,我得到了一个假值。我可以用我所做的来更新我的答案。
    • 其实我想我找到了问题所在。在服务器端,localstorage.getItem('toke') 返回 null,但在浏览器中返回实际令牌值
    • 是的,请更新问题。 LocalStorage 不应该在服务器中可用,只能在浏览器中使用。
    • 是的!我已经做了。如果 LocalStorage 在服务器中不可用,不知道如何解决问题。
    【解决方案2】:

    这是因为您使用了localStorage。您的应用程序的服务器端版本无法访问本地存储(就像它无法访问任何浏览器对象上的windownavigator),因此它认为用户未连接。

    在使用 Angular 通用和身份验证时,您可以使用服务器可以访问的 cookie。

    有一些可用的库,但从我看来,它们还没有完全准备好与 angular 9 一起使用:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多