Angular 6:使用 forkJoin 进行错误处理

tt0*_*206 13 rxjs angular

我不确定如何在使用forkJoin 时获取特定 api 调用的异常消息

我写的代码如下

    reqs = [];
    if (shouldUpdatePhone) {
       reqs.push(this.customerService.updatePhone(phoneUpdateRequest))
    }
    if (shouldUpdateAddress) {
       reqs.push(this.customerService.updateAddress(addressUpdateRequest))
    }

    forkJoin(reqs).subscribe(result => {
       console.log('result :', result);

    }, error => {
      //How to get error message for particular api call?
});
Run Code Online (Sandbox Code Playgroud)

如果一个/两个 api 由于某种原因失败。我应该如何决定哪个 api 抛出异常。

Joã*_*tti 22

有一种处理错误的方法forkJoin不会阻止您使用此运算符。关键实际上是另一个答案的一部分。

是的,forkJoin会在第一个错误时完成,你有点不知道它来自哪个 observable,但是如果你处理内部 observables 中的错误,你可以很容易地实现这一点。

考虑一下你的代码的这个(缩小的)部分,与@Explosion Pills 的答案混合在一起:

reqs: Observable<any>[] = [];
if (shouldUpdatePhone) {
  reqs.push(
    this.service.updatePhone(phone)
      .pipe(
        catchError((err) => {
          // Handle specific error for this call
          return of(undefined)),
        }
      )
  );
}
if (shouldUpdateAddress) {
      reqs.push(
        this.service.updateAddress(address)
          .pipe(
            catchError((err) => {
              // Handle specific error for this call
              return of(undefined)),
            }
          )
      );
    }
Run Code Online (Sandbox Code Playgroud)

然后,对于您的forkJoin

forkJoin(reqs).subscribe(result => console.log(result));
Run Code Online (Sandbox Code Playgroud)

现在考虑两个 API 调用分别返回一个对象,如{phone: string}{address: string}。你的result将是:

[{phone: '123-456'}, {address: 'Happy Street, 123'}]
Run Code Online (Sandbox Code Playgroud)

但是好的,这是基本的forkJoin,错误处理部分在哪里?
考虑您的一个调用失败,返回的错误包含一个状态代码和一条消息,您想知道它们。

正如我所说,forkJoin如果您在内部 observable 中处理错误,则不会完成,这就是为什么我们有

  .pipe(
    catchError((err) => {
      // Handle specific error for this call
      return of(undefined)),
    }
  )
Run Code Online (Sandbox Code Playgroud)

如果您的第一次调用 (updatePhone) 失败,您的结果将是

[undefined, {address: 'Happy Street, 123'}]
Run Code Online (Sandbox Code Playgroud)

因为您没有让 observable 死亡,并且在出错时返回了一个带有return of(undefined).

这使您有可能处理这样的错误(内部catchError):

catchError((err) => {
  if (err.status === 409) {
    // do something
  }
  return of(undefined)),
}
Run Code Online (Sandbox Code Playgroud)

或者像这样

...
catchError((err) => {
  return of({error: err, isError: true})),
}
...
forkJoin(...).subscribe(result => {
  result.forEach(r => {
    if (r.isError) {
      // do something
    }
  });
});
Run Code Online (Sandbox Code Playgroud)

您所有的 API 调用都将完成,您可以随时处理它,也可以等待所有 API 调用返回并仅处理返回错误的那些,这样您就可以获得错误可以提供给您的任何信息并专门处理它.


Exp*_*lls 6

你不能,因为forkJoin它会在任何 observables 遇到的第一个错误上抛出错误。如果发出的错误中没有任何内容告诉您它来自于检查错误代码,那么您可以在从服务调用创建 observable 时选择处理错误。

reqs = [];
if (shouldUpdatePhone) {
   reqs.push(
     this.customerService.updatePhone(phoneUpdateRequest).pipe(catchError(() => {
       throw 'phoneUpdateError';
     });
   )
}
if (shouldUpdateAddress) {
   reqs.push(
     this.customerService.updateAddress(phoneUpdateRequest).pipe(catchError(() => {
       throw 'addressUpdateError';
     });
   )
}
Run Code Online (Sandbox Code Playgroud)

现在您可以检查抛出了哪个错误。不过,您不必通过错误处理来执行此操作;您还可以将错误映射到成功的响应并进行处理。

最终我会建议结合这些 API 调用。