【问题标题】:Calling global handleError function inside catchError RxJs 6 (Migrating from RxJs 5)在 catchError RxJs 6 中调用全局 handleError 函数(从 RxJs 5 迁移)
【发布时间】:2019-11-14 11:57:26
【问题描述】:

最近我将我的 Ionic 3 项目升级到了 Ionic 4,通过这次升级还更新了其他几个包(Angular 5 --> 8 和 RxJs 5.5 --> 6.5)。代码中所需的大部分更改都进展顺利,但有一个更改我无法解决。

在我的一项服务中,我有一个执行 API 获取 (GET) 的函数。提取 (http GET) 中的任何错误都在全局错误函数中处理。在我的旧 Ionic 3 / RxJs 5~ 应用程序中,这是按如下方式完成的:

public fetch(): Observable<T[]> {
    let _path: string = this.path; 
    const url = this.getUrl(_path);

    return this.http
        .get(url, this.options)
        .catch(this.handleError);
}

handleError 函数在另一个服务中定义:

protected handleError(error: any) {
    const errMsg = (error.message) ? error.message :
      error.status ? `${error.status} - ${error.statusText}` : 'Server error';

    this.logger.error('API endpoint: ' + this.path, errMsg);
    this.showErrorToast(); // not async in Ionic 3

    return Observable.throw(errMsg);
}

在我的 Ionic 4 / RxJs 6 应用程序中,我试图重新创建它但没有成功。 我已阅读并更改以下内容:

  • catch 已弃用,应替换为 catchError
  • Observable.throw 也已弃用,应替换为 throwError

所以我的新实现如下所示:

public fetch(): Observable<T[]> {
    let _path: string = this.path; 
    const url = this.getUrl(_path);

    return this.http
        .get(url, this.options)
        .pipe(
          catchError(() => { // this line is returning a error
            this.handleError;
          }
        ));  
}

protected handleError(error: any) {
    const errMsg = (error.message) ? error.message :
      error.status ? `${error.status} - ${error.statusText}` : 'Server error';

    this.logger.error('API endpoint: ' + this.path, errMsg);
    this.showErrorToast(); // now async in Ionic 4

    return throwError(errMsg); // Changed this 
}

但是,catchError(() =&gt; 返回以下错误:

Argument of type '() => void' is not assignable to parameter of type '(err: any, caught: Observable<Object>) => ObservableInput<any>'.
  Type 'void' is not assignable to type 'ObservableInput<any>'

在尝试了其他几件事后,我有点不知道如何解决这个问题,有什么想法或建议吗?

更新

在实施了一些建议的解决方案后,我一直得到与前一个相同但不同的错误:

 Type 'Observable<Object>' is not assignable to type 'Observable<T[]>'.
      The 'Object' type is assignable to very few other types. Did you mean to use the 'any' type instead?
        Type 'Object' is missing the following properties from type 'T[]': length, pop, push, concat, and 26 more

所以经过一番调查,我想出了这个(使用@theMayer提出的解决方案):

我变了:

return this.http
    .get(url, this.options)
    .pipe(
      catchError(e => {
        this.handleError(e);
        return EMPTY;
      }
    ));

到:

return this.http
        .get<T[]>(url, this.options)
        .pipe(
          catchError(e => {
            this.handleError(e);
            return EMPTY;
          }
        ));

以上更改消除了错误,但我不确定这是要走的路吗? fetch 函数将遍历定义 API 端点的多个其他服务。

【问题讨论】:

  • 使用catchError(this.handleError)
  • @fridoo - 它可以在语法上工作,但是当直接引用一个函数时,this 在运行时变得不受约束(除非他们已经在更高版本的 typescript/javascript 中修复了这个问题)。
  • @theMayer 是的,但是正如 OP 之前使用的 catch(this.handleError)(我认为一切正常)切换到 catchError(this.handleError) 应该完全一样。如果要保留当前上下文,可以使用 catchError(this.handleError.bind(this))
  • 或者你可以写catchError(e =&gt; this.handleError(e)) -> 但它需要在下面更改方法签名。
  • 好的,所以你有一个不同的问题 - 你似乎不明白所涉及的类型。你有一个称职的IDE吗?我推荐安装了 Angular 语言服务的 Visual Studio 代码。

标签: angular ionic-framework rxjs


【解决方案1】:

您被 RxJs 6 中的语法更改绊倒了。错误消息看起来令人困惑,但它只是说您的错误处理程序必须返回一个 observable(所有可管道操作符都必须返回)。但是,它并不关心 observable 是 of 的什么。

因此,需要进行简单的重写(请注意,EMPTY 可能不是您在此处所需要的,但它适用于我的代码):

import { EMPTY } from 'rxjs';

public fetch(): Observable<T[]> {
    let _path: string = this.path; 
    const url = this.getUrl(_path);

    return this.http
        .get(url, this.options)
        .pipe(
          catchError(e => {        // need to capture the 'e' here...
            this.handleError(e);   // pass to your function
            return EMPTY;          // and return empty
          }
        ));  
}

protected handleError(error: any) {
    const errMsg = (error.message) ? error.message :
      error.status ? `${error.status} - ${error.statusText}` : 'Server error';

    this.logger.error('API endpoint: ' + this.path, errMsg);
    this.showErrorToast(); // now async in Ionic 4
}

删除这个:

返回 throwError(errMsg); //改变了这个

【讨论】:

  • 我实现了这个解决方案,但现在我得到了一个不同的错误,请参阅我的更新主帖。
【解决方案2】:

我可以看到你只将函数引用放在 catchError() 中,catchError 需要返回一个 observable。试试这个

catchError(e => { 
            return this.handleError(e);
          }

【讨论】:

    【解决方案3】:

    也许你需要这样使用:

    .pipe(catchError(this.handleError);
    

    如果你想要一个通用的错误处理方法,你可以使用 Angular 内置的 ErrorHandler。有了这个,你可以捕捉到运行时发生的所有错误,你可以展示一个烤面包机或任何你想要的东西。如果您使用这种方法,那么您不需要在所有服务中实现错误捕获登录。这将在发生故障时自动触发。

    在您的 AppModule in providers 中导入您的自定义错误处理程序服务:

    providers: [{ provide: ErrorHandler, useClass: RuntimeErrorHandlerService }]
    

    自定义错误处理服务:

    @Injectable()
    export class RuntimeErrorHandlerService implements ErrorHandler {
      constructor(private injector: Injector) {}
    
      handleError(error: any) {
        // Show your toaster or do whatever you want
        const toasterService = this.injector.get(ToasterService);
        toasterService.show(error);
      }
    }
    

    可以检查是http请求错误还是运行时错误。 角度文档:https://angular.io/api/core/ErrorHandler

    【讨论】:

    • 这并不是用户真正想要做的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-08
    • 2018-11-27
    • 2018-11-09
    • 1970-01-01
    • 2021-01-16
    • 2017-05-07
    • 2019-08-02
    相关资源
    最近更新 更多