【问题标题】:A new duplicate sign-out HTTP request is sent every time the user logs out: Angular, RxJs每次用户注销时都会发送一个新的重复注销 HTTP 请求:Angular、RxJs
【发布时间】:2023-03-10 19:23:01
【问题描述】:

问题描述

首先,让我先说我在前端使用 Angular 10 和 Nebular UI 库,在后端使用 Node.js - end API,以及 JWT 与电子邮件/密码策略 进行身份验证。我注意到每次用户在不刷新应用程序的情况下登录并退出时,都会向服务器发出一个新的重复退出请求(正在发送多个 http 请求)。 如果您在退出后刷新应用程序,问题就会消失。我不确定我是否跳过了某些内容,或者我只是不知道使用 JWT 注销并重新登录的正确方法,但我几天来一直试图找到解决这个问题的方法,但没有成功所以我渴望得到一些帮助。

当前行为:

如果用户多次登录并再次退出,向服务器发出的退出请求会重复。无论您是否使用 http 拦截器(NbAuthJWTInterceptor 或其他),此问题仍然存在。

预期行为:

如果用户要重新登录并重新注销,应该不会向服务器发出多余的注销请求,无论用户重复这些步骤多少次而不刷新应用程序.

重现步骤:

  1. 用户第一次登录时一切正常,并且在您注销时没有向服务器发出重复请求。
  2. 在您第二次重新登录第二次退出而不刷新应用程序后,您向服务器发出的第二次退出请求将发送退出重复的退出请求(向服务器发送 2 个相同的退出请求)。
  3. 如果用户第三次再次登录第三次退出登录,则会向服务器发送 3 个退出请求(一个共发出 3 个相同的请求)。
  4. 如果用户再次登录并退出,退出请求将重复发送一次,总共会发出 4 个相同的退出请求。这种情况会无限期地持续下去。

这是我的开发工具网络选项卡中这 4 个步骤的屏幕截图(在登录和退出 4 次之后):

相关代码: 在客户端,我有 header.component.ts 文件,从中启动注销过程:

...
ngOnInit() {
    // Context Menu Event Handler.
    this.menuService.onItemClick().pipe(
      filter(({ tag }) => tag === 'my-context-menu'),
      map(({ item: { title } }) => title),
    ).subscribe((title) => {
      // Check if the Logout menu item was clicked.
      if (title == 'Log out') {

        // Logout the user.
        this.authService.logout('email').subscribe(() => {
          // Clear the token.
          this.tokenService.clear()
          // Navigate to the login page.
          return this.router.navigate([`/auth/login`]);
        });

      }
      if (title == 'Profile') {
        return this.router.navigate([`/pages/profile/${this.user["_id"]}`]);
      }
    });
}
...

在服务器端,有返回成功 200 响应的注销 API 路由:

// Asynchronous POST request to logout the user.
router.post('/sign-out', async (req, res) => {
    return res.status(200).send();
});

【问题讨论】:

    标签: angular rxjs jwt rxjs-observables nebular


    【解决方案1】:

    您正在订阅另一个订阅。这会导致每次调用 this.menuService.onItemClick() 时都会进行另一个订阅。

    您需要通过使用适当的 Rxjs 运算符(exhaustMap、concatMap、switchMap、mergeMap)来使用扁平化策略。

    在你的情况下,我会像这样重构(不要忘记取消订阅ngOnDestroy 中的每个订阅)

    const titleChange$ = this.menuService.onItemClick()
      .pipe(
        filter(({ tag }) => tag === 'my-context-menu'),
        map(({ item: { title } }) => title)
      );
    
    this.logOutSubscription = titleChange$.pipe(
      filter((title) => title == 'Log out'),
      exhaustMap((title) => this.authService.logout('email')),
      tap(() => {
        this.tokenService.clear()
        this.router.navigate([`/auth/login`]);
    })
    .subscribe();
    
    this.profileNavSubscription = titleChange$
      .pipe(
        filter((title) => title == 'Profile'),
        tap(title => {
          this.router.navigate([`/pages/profile/${this.user["_id"]}`])
        })
       .subscribe();
    

    `

    【讨论】:

    • 非常感谢!它进行了一些调整!
    猜你喜欢
    • 2017-07-06
    • 2020-02-02
    • 2014-11-29
    • 2018-01-24
    • 2018-08-01
    • 1970-01-01
    • 2012-09-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多