【问题标题】:Handle business error in api request处理api请求中的业务错误
【发布时间】:2017-01-27 16:21:32
【问题描述】:

我有一些 api 以格式返回响应

{
  code: 0, // 0 is Ok, all other values is error
  data: [{...}, {...}, {...}, ...], // data objects
  message: "" // empty when ok or some error message in other cases
}

我尝试为这个api创建通信服务

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';

interface IApiResponse<T> {
  code: number;
  data: Array<T>;
  message: string;
}

@Injectable()
export class ApiService {

  constructor( 
    private http: Http 
  ) { }

  apiGet<T>(url: string): Observable<Array<T>> {
    return this.http.get(url)
            .map((res: Response) => res.json())
            //.map((api: IApiResponse<T>) => api.code === 0 ? api.data : Observable.throw(api.message))
            .mergeMap((api: IApiResponse<T>) => api.code === 0 ? api.data : Observable.throw(api.message))
            .catch(err => Observable.throw(err));
  }

}

我想在代码字段不等于 0 时引发异常,并在订阅的错误部分返回消息。 但是当我在 map 中返回 Observable.throw 时,它作为订阅中的数据返回,而不是作为错误返回。 当我尝试使用mergeMap 时,异常在订阅函数中按预期返回错误,但数据数组中的每个对象都返回数据。这不适合我。 可能我必须为此使用其他一些可观察的函数吗?

组件中的服务使用

import { Component, OnInit } from '@angular/core';

interface ITestItem {
  id: number;
  title: string;
}

@Component({
  selector: 'app-main',
  templateUrl: './main.component.html',
  styles: []
})
export class MainComponent implements OnInit {

  constructor(
    private apiService: ApiService
  ) { }

  ngOnInit() {
    this.apiService.apiGet<ITestItem>('/api/test')
      .subscribe(
        // only data when code = 0 or nothing
        data => console.log("data section:", data), 
        // handle http errors and message when code != 0
        error => console.log("error section:", error), 
        () => console.log("api request completed")
      );
  }

}

【问题讨论】:

    标签: angular rxjs observable


    【解决方案1】:

    发生这种情况的原因是,如果可能,mergeMap 会将结果转换为 Observable。由于您的数据是一个数组,因此它会将其转换为 Observable 并发出包含的每个元素。

    .mergeMap 中使用Rx.Observable.of() 包装您的数据,以将其保存为数组发射

    【讨论】:

    • 是的,它有效!但我不明白为什么 Observable.throw 在 map 和 mergeMap 中的工作方式不同。
    • map 函数不会将结果转换为 Observable,因此当你的 map 函数返回一个 Observable.throw 时,它将是它向 subscribe 的 next 函数发出的值。
    【解决方案2】:

    基于RxJS doc,您非常接近。您需要像这样抛出异常:

     Observable.throw(new Error(api.message));
    

    希望有帮助

    编辑更多信息

    服务,根据您的需要进行任何必要的更改。

    getTestData(): any {
        return this.http.get("testUrlShouldThrowError")
          .map((api: any) => {
            if (api.code === 0) {
              return <IApiResponse<Test>>api.data
            }
            else {
              return Observable.throw(new Error("Error!"))
            }
          });
      }
    

    订阅:

    this.testService.getTestData().subscribe(
          data => console.log(data.error.message),
        )
    

    【讨论】:

    • .map((api: IApiResponse) => api.code === 0 ? api.data : Observable.throw(new Error(api.message))) 在数据中返回 ErrorObservable订阅的一部分。
    • @avvensis 是的,但您可以在订阅中访问您的错误消息error =&gt; console.log("error section:", error.error.message)
    • 我该怎么办?
    • 我重复了您的代码并在控制台中获取输出:数据部分:ErrorObservable... console.log(data.error.message) 不起作用,因为 TypeScript 需要 ITestItem 在数据中,但它没有有错误属性。所以我应该每次在每个组件中检查数据类型它的接口数组或 ErrorObservable 。这对我来说不是个好主意。
    • 注意到... 3 行...getTestData(): any 返回任何类型,.map((api: any) 也是任何类型...如果成功 return &lt;IApiResponse&lt;Test&gt;&gt;api.data 在您的情况下将其转换为测试类型 ITestItem。
    猜你喜欢
    • 2021-12-29
    • 1970-01-01
    • 2019-03-05
    • 1970-01-01
    • 2011-11-06
    • 1970-01-01
    • 2018-08-28
    • 1970-01-01
    • 2014-09-10
    相关资源
    最近更新 更多