如何使用Rxjs switchMap引发throwError

时间:2019-05-15 01:38:30

标签: javascript browser rxjs rxjs6

我已经为获取函数创建了一个包装器。根据下面的代码,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。

2 个答案:

答案 0 :(得分:4)

获取不会为您抛出错误

https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

  

从fetch()返回的Promise不会因HTTP错误状态而拒绝   即使响应是HTTP 404或500,它也会解析   通常(将ok状态设置为false),并且只会在   网络故障或是否有任何阻止请求完成的事情。

更新: 看来您的api调用正在返回401,并且在获取承诺中将被拒绝,但是您仍然不能依靠获取来正确拒绝。请参阅以下主题

https://github.com/github/fetch/issues/201

对于您的代码,switchMap无法处理的原因是您返回的不是throw Promise的throwError(您将函数标记为async)

throwError(...)更改为throwError().toPromise()可以正常工作。但同样不要依赖提取来正确拒绝

答案 1 :(得分:1)

删除async中的switchMap,然后使用of返回一个Observable。

const http = (url) => 
  from(fetch(new Request(url))
    .pipe(
      retry(3),
      catchError(error => { // fetch will throw error if page not found.
        return of(new Response(null, { status: 404, statusText: 'Page not found' }));
      }),
      switchMap((response: Response) =>        
        response.ok
          ? of(response) // return an observable here using 'of'
          : throwError(response)
      ),
    );

async导致switchMap返回您所返回内容的Observable。因此,在您的switchMap中,如果response.ok == false返回了一个Observable<Observable<never>>,则它向成功回调发出了一个Observable<never>