angular - Varför får jag "undefined" från Observable i auth guard när jag använder pipe(), medan subscribe() fungerar men jag får ett fel?


Jag bygger en autentiseringsapp med PEAN-stacken (dvs. PostgreSQL - ExpressJS - Angular - NodeJS).

Problem

Jag har ett problem med min autentiseringsskydd:

  • Om jag använder subscribe() får jag det förväntade resultatet i konsolen. ✔ - FUNGERAR
  • Om jag använder pipe() får jag undefined i konsolen. ✖ - FUNGERAR INTE

if-signed-in.guard.ts

import { CanActivateFn } from '@angular/router';
import { AuthService } from '../services/auth/auth.service';
import { inject } from '@angular/core';
import { tap, map } from 'rxjs/operators';
import { Router } from '@angular/router';

export const IfSignedIn: CanActivateFn = (route, state) => {
  const auth = inject(AuthService);
  const router = inject(Router);
    
  auth.getSignInStatusObserver().subscribe((res: any) => {
    console.log(res);
  });

  return auth.getSignInStatusObserver().pipe(
    tap((status) => {
      console.log(status);
    }),
    map((status) => {
      console.log(status);
      if (status) {
        if (status.success === true) {
          return true;
        } else {
          router.navigate(['/dashboard']);
          return false;
        }
      } else {
        router.navigate(['/dashboard']);
        return false;
      }
    })
  );
};

Skärmdump:

Vad jag har försökt

Jag försökte implementera samma logik inuti subscribe():

if-signed-in.guard.ts

import { CanActivateFn } from '@angular/router';
import { AuthService } from '../services/auth/auth.service';
import { inject } from '@angular/core';
import { Router } from '@angular/router';

export const IfSignedIn: CanActivateFn = (route, state) => {
  const auth = inject(AuthService);
  const router = inject(Router);

  auth.getSignInStatusObserver().subscribe((res: any) => {
    if (res) {
      if (res.success === true) {
        return true;
      } else {
        router.navigate(['/dashboard']);
        return false;
      }
    } else {
      router.navigate(['/dashboard']);
      return false;
    }
  });
};

Men jag får följande fel:

src/app/auth/guards/if-signed-in.guard.ts:7:14 - fel TS2322: Typen '(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => void' kan inte tilldelas typen 'CanActivateFn'. Typen 'void' kan inte tilldelas typen 'boolean | UrlTree | Observable | Promise'.

7 export const IfSignedIn: CanActivateFn=(route, state) => {

Fråga

Varför får jag undefined från Observable i autentiseringsvakt när jag använder pipe(), medan subscribe() fungerar men jag får ett fel?


REDIGERA 1

Jag har provat koden som föreslogs av @MatthieuRiegler, men jag får fortfarande exakt samma svar som i skärmdumpen ovan.

if-signed-in.guard.ts

import { CanActivateFn } from '@angular/router';
import { AuthService } from '../services/auth/auth.service';
import { inject } from '@angular/core';
import { filter, tap, map } from 'rxjs/operators';
import { Router } from '@angular/router';

export const IfSignedIn: CanActivateFn = (route, state) => {
  const auth = inject(AuthService);
  const router = inject(Router);

  auth.getSignInStatusObserver().subscribe((res: any) => {
    console.log(res);
  });

  return auth.getSignInStatusObserver().pipe(
    filter((status) => status !== undefined),
    tap((status) => {
      console.log(status);
    }),
    map((status) => {
      console.log(status);
      if (status) {
        if (status.success === true) {
          return true;
        } else {
          router.navigate(['/dashboard']);
          return false;
        }
      } else {
        router.navigate(['/dashboard']);
        return false;
      }
    })
  );
};

REDIGERA 2

Min app beter sig konstigt. Nu har jag följande kod:

if-signed-in.guard.ts

import { CanActivateFn } from '@angular/router';
import { AuthService } from '../services/auth/auth.service';
import { inject } from '@angular/core';
import { filter, tap, map } from 'rxjs/operators';
import { Router } from '@angular/router';

export const IfSignedIn: CanActivateFn = (route, state) => {
  const auth = inject(AuthService);
  const router = inject(Router);

  return auth.getSignInStatusObserver().pipe(
    filter((status) => status !== undefined),
    tap((status) => {
      console.log('Tap: ', status);
    }),
    map((status) => {
      console.log('Map: ', status);
      if (status) {
        if (status.success === true) {
          return true;
        } else {
          router.navigate(['/dashboard']);
          return false;
        }
      } else {
        router.navigate(['/dashboard']);
        return false;
      }
    })
  );
};

Om jag klickar på Redigera profil-knappen fungerar allt som förväntat. Om jag skriver i sökfältet http://localhost:4200/profile/edit-profile ser det ut som om något är fel med att sända värden eftersom jag får undefined, och eftersom filter() fungerar får jag ingenting i konsolen.

Också händer samma sak vid uppdatering av sidan. Det verkar som att autentiseringsskyddet inte fungerar vid uppdatering av sidan.

Skärmdump:


REDIGERA 3

Jag använder en interceptör för att ställa in inloggningsstatus enligt följande:

sign-in-status.tjänst.ts

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpEvent, HttpRequest, HttpHandler, HttpResponse } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { tap, catchError } from 'rxjs/operators';
import { AuthService } from 'src/app/auth/services/auth/auth.service';

@Injectable({
  providedIn: 'root',
})
export class SignInStatusService implements HttpInterceptor {
  intercept(httpRequest: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(httpRequest).pipe(
      tap((event: HttpEvent<any>) => {
        if (event instanceof HttpResponse && httpRequest.url.endsWith('api/get-user') && event.status === 200) {
          this.authService.setSignInStatus({ success: true, response: event.body });
        }
      }),
      catchError((err: any) => {
        if (httpRequest.url.endsWith('api/get-user')) {
          this.authService.setSignInStatus({ success: false, response: err });
        }
        return throwError(() => err);
      })
    );
  }

  constructor(private authService: AuthService) {}
}

Svar #1

Ditt problem ligger någon annanstans. Som du kan se får du ett undefined som första värde av din subscribe.

Genom att göra en subscribe utan att stänga den, lever den längre än användningen av CanActivateFn.

Min gissning är att du upplever en tävlingssituation. Din observable avger ett status för sent för CanActivateFn.

Din getSignInStatusObserver bör inte sända undefined, du filtrerar det med pipe(filter(status => status !== undefined)). Det borde lösa ditt problem!

Relaterade artiklar