如何从 Angular httpClient 检索 Observable<boolean>(如果 200 则为真,如果 404 则为假)

How to retrieve an Observable<boolean> from Angular httpClient (true if 200, false if 404)

在 angular 中,我有一个用于检查用户注册表单的异步验证器 如果电子邮件已存在于数据库中。 它使用 HEAD 方法调用我的 Rest API 的端点,如果找到电子邮件,则 returns 为 Http 200 Ok 状态,如果未找到则为 404(我不确定它是否是正确的 Rest练习思想)。 但我无法弄清楚如何将该 http 调用转换为我的验证器所期望的 Observable。

我在不考虑表格的情况下进行此操作的图层是:

AsyncValidator -> authService.isEmailTaken() -> dataManagementService.headCall()

我的验证者:

export const uniqueEmailValidator = (authService: AuthService, time: number = 500) => {
  return (input: FormControl) => {
    return timer(time).pipe(
      switchMap(() => authService.isEmailTaken(input.value)),
      map(isTaken => {
        console.log(isTaken);
        return isTaken ? { uniqueEmail: true } : null;
      })
    );
  };
};

AuthService.ts:

  public isEmailTaken(email: string): Observable<boolean> {
    const params = new Map();
      params.set('email', email);
      return this.dataManagementService.headResource(
        this.authURI + this.registerURI,
        params
      ).pipe(
        map(
         () => {
           console.log('success');
           return true;
         },
         () => {
           console.log('error');
           return false;
         }
     )
    );
  }

我的 http 调用:

  public headResource(url: string, paramMap?: Map<string, string>): Observable<any> {
    const params = this.getHttpParams(paramMap);
    console.log('Sending HEAD request to server :');
    console.log(this.baseUrl + url);
    return this.httpClient.head(
      this.baseUrl + url,
      {params}
    );
  }

My validator should be valid when the status code is 404 and invalid when is 200, but though it works on 200, it has no efffect on 404. I'm not very confortable using rxjs.
Is there something i'm missing ? Or should i change the approach with the backend service sending a boolean, or maybe a 204 status code if not found ?
Thanks a lot for help!

==============编辑=======================

感谢马丁的评论,我设法通过更改我的 authService 的 isEmailTaken 方法并使用 catchError 使其工作:

  public isEmailTaken(email: string): Observable<boolean> {
    const params = new Map();
    params.set('email', email);
    return this.dataManagementService.headResource(
      this.authURI + this.registerURI,
      params
    ).pipe(
      map(
      () => {
        return true;
      }),
      catchError(error => {
        if (error.status === 404) {
          return of(false);
        }
      })
    );
  }

对于 Angular 的 HttpClient 404 响应将变成 error 通知,而您的验证器期望 boolean next 通知。所以问题是如何把error通知变成next。幸运的是,使用 catchError() 运算符非常容易:

import { of, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';

this.httpClient.head().pipe(
  catchError(error => {
    if (error.status === 404) {
      return of(false); // emit `false` as next notification instead of the original error
    }
    return throwError(error); // rethrow other status codes as error
  }),
);

顺便说一句,map 仅适用于 next 通知。我不会以任何方式处理 errors。