在 rxjs ajax.map 调用中处理异常

Handle exception in rxjs ajax.map call

我根据“fetch user demo" on the redux-observable website.

创作了一部史诗

我只是想知道如何向 ajax 请求添加错误处理。我的尝试:

const fetchCategoriesEpic = action$ =>
  action$.ofType(FETCH_CATEGORIES)
    .mergeMap(() =>
      ajax.getJSON(`http://localhost:4000/categories`)
        .map(
          response => fetchCategoriesFulfilled(response),
          error => console.log(error)
        )
    )

我正在测试,而我正在调用的 API 正在测试错误处理。仍然在控制台中得到这个并且应用程序崩溃:

ExceptionsManager.js:71 Unhandled JS Exception: ajax error 0

如果 this is the official docs 那么我是否应该摆脱地图并改用订阅?

我改成了这样:

import 'rxjs/add/operator/catch'

const fetchCategoriesEpic = action$ =>
  action$.ofType(FETCH_CATEGORIES)
    .mergeMap(() =>
      ajax.getJSON(`http://localhost:4000/categories`)
        .map(
          response => fetchCategoriesFulfilled(response)
        ).catch( err => console.log(err))
    )

但是得到了:

You provided undefined where a stream was expected. You can provide an obserable, promise, array or iterable

更改为(根据 Jay Phelps 的回答 here):

const fetchCategoriesEpic = action$ =>
  action$.ofType(FETCH_CATEGORIES)
    .mergeMap(() =>
      ajax.getJSON(`http://localhost:4000/categories`)
        .map(response => fetchCategoriesFulfilled(response))
        .catch( err => Observable.of(err.xhr.response))
    )

得到:

Actions must be plain objects. Use custom middleware for async actions

我做错了什么?

https://github.com/Reactive-Extensions/RxJS-DOM is for RxJS v4, not v5. The docs for v5 are here: http://reactivex.io/rxjs/ and the source code here https://github.com/ReactiveX/rxjs.

这确实令人困惑,但由于复杂的原因,这是不幸的现实。


You provided undefined where a stream was expected. You can provide an obserable, promise, array or iterable

您收到此错误的原因确实是,您不是 return 需要的 catch 运算符使用流。

redux-observable 文档在此处提供了错误处理方法:https://redux-observable.js.org/docs/recipes/ErrorHandling.html

所以它看起来像这样:

const fetchCategoriesEpic = action$ =>
  action$.ofType(FETCH_CATEGORIES)
    .mergeMap(() =>
      ajax.getJSON(`http://localhost:4000/categories`)
        .map(
          response => fetchCategoriesFulfilled(response)
        )
        .catch(error => Observable.of({
          type: FETCH_CATEGORIES_REJECTED,
          error
        }))
    )

如果你真的不想捕获错误和return另一个Observable(比如单个错误操作的Observable)那么你可以使用.do() 只记录错误:

const fetchCategoriesEpic = action$ =>
  action$.ofType(FETCH_CATEGORIES)
    .mergeMap(() =>
      ajax.getJSON(`http://localhost:4000/categories`)
        .map(
          response => fetchCategoriesFulfilled(response)
        )
        .do({
          error: err => console.log(err)
        })
    )

但是,如果您没有发现错误,它将向上传播到源链,终止此 Epic,然后继续传播终止您的根 Epic,从而使您的应用可能无法使用。

虽然我不推荐这样做,但如果你真的想捕获错误但只是吞下它而不进行分派和错误操作,你可以这样做:

const fetchCategoriesEpic = action$ =>
  action$.ofType(FETCH_CATEGORIES)
    .mergeMap(() =>
      ajax.getJSON(`http://localhost:4000/categories`)
        .map(
          response => fetchCategoriesFulfilled(response)
        )
        .catch(error => {
          console.error(error);
          return Observable.empty();
        })
    )

再次强调,我强烈建议不要这样做——如果有一个错误你足够关心来捕捉它,你可能应该以某种方式处理它,例如通过分派错误操作和处理来向用户显示错误那。


编辑:根据您的新增内容

.catch( err => Observable.of(err.xhr.response))

Actions must be plain objects. Use custom middleware for async actions

确实,您的史诗现在发出错误的 XHR 响应,而不是 redux 操作。您的史诗只能发出动作。