首页 > 解决方案 > 如何使用 Rxjs switchMap 来抛出错误

问题描述

我已经为 fetch 函数创建了一个包装器。根据下面的代码,test_3 通过了,但是 test_1 和 test_2 怎么会命中成功回调而不是错误回调呢?我怀疑我使用 throwError 的方式有问题。

import { from, throwError } from 'rxjs'; // version 6.5.2
import { retry, catchError, switchMap } from 'rxjs/operators';

function getBody(response: Response): Promise<any> {
  const headers = response.headers;

  if (headers.has('content-type')) {
    const contentType: string = headers.get('content-type');
    if (contentType.includes('json')) return response.json();
  }
  return response.text();
}

const http = (url) => 
  from(fetch(new Request(url))
    .pipe(
      retry(3),
      catchError(error => { // fetch will throw error if page not found.
        console.log('hit catchError')
        return of(new Response(null, { status: 404, statusText: 'Page not found' }));
      }),
      switchMap(async (response: Response) => {
        console.log('response.ok = ', response.ok);
        return response.ok
          ? getBody(response) // all status >= 200 and < 400 
          : throwError({ 
              status: response.status, 
              statusText: response.statusText, 
              body: await getBody(response) 
            });
      }),
    );

// test_1
http('http://this_url_not_exists.com').subscribe(
  response => console.log('should not hit this'),
  errorResponse => console.log('should errorResponse.status = 404'),
);
// test_1 console result:
// hit catchError
// response.ok = false
// should not hit this

// test_2
http('http://this_url_require_authentication.com').subscribe(
  response => console.log('should not hit this'),
  errorResponse => console.log('should errorResponse.status = 401'),
);
// test_2 console result:
// response.ok = false
// should not hit this

// test_3
http('http://myurl.com').subscribe(
  response => console.log('should hit this'),
  errorResponse => console.log('should not hit this'),
);
// test_3 console result:
// response.ok = true
// should hit this

请不要建议我使用 rxjs 的 ajax。

标签: javascriptbrowserrxjsrxjs6

解决方案


你可以直接在里面返回一个 Promise switchMap

switchMap(response => response.ok 
  ? getBody(response) 
  : getBody(response).then(body => {
    throw { status: response.status, statusText: response.statusText, body } 
  }))
)

不要async使用switchMap(async (response: Response) => { })

问题是这async会导致switchMap返回任何你返回的 Observable。所以在你的switchMapifresponse.ok == false你返回一个which 然后向你的成功回调Observable<Observable<never>>发出一个。Observable<never>


这里有一些在内部抛出错误的一般方法switchMap

1. 返回一个错误的 Observable。

switchMap(response => response.ok 
  ? of(successObject) 
  : throwError(errorObject)
)

2.直接抛出错误

switchMap(response => {
  if (response.ok) {
    return of(successObject)
  } else {
    throw errorObject
  }
})

3. 返回一个错误的 Promise

switchMap(response => response.ok
  ? Promise.resolve(successObject)
  : Promise.reject(errorObject)
)

推荐阅读