javascript - How to use Rxjs switchMap to throwError - Stack Overflow

I have create a wrapper for fetch function. Based on the code below, test_3 passed but how e test_1 and

I have create a wrapper for fetch function. Based on the code below, test_3 passed but how e test_1 and test_2 hit success callback instead of error callback? I suspect there is something wrong in the way I use 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('').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('').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('').subscribe(
  response => console.log('should hit this'),
  errorResponse => console.log('should not hit this'),
);
// test_3 console result:
// response.ok = true
// should hit this

Please do not propose me to use rxjs's ajax.

I have create a wrapper for fetch function. Based on the code below, test_3 passed but how e test_1 and test_2 hit success callback instead of error callback? I suspect there is something wrong in the way I use 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.').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.').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.').subscribe(
  response => console.log('should hit this'),
  errorResponse => console.log('should not hit this'),
);
// test_3 console result:
// response.ok = true
// should hit this

Please do not propose me to use rxjs's ajax.

Share Improve this question edited May 16, 2019 at 3:40 Simon asked May 15, 2019 at 1:38 SimonSimon 1,5363 gold badges17 silver badges25 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 3

fetch won't throw error for you

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

The Promise returned from fetch() won’t reject on HTTP error status even if the response is an HTTP 404 or 500. Instead, it will resolve normally (with ok status set to false), and it will only reject on network failure or if anything prevented the request from pleting.

Update: Looks like your api call is returning 401 and will be rejected in fetch promise, but you still can't rely on fetch to reject properly. please see the below thread

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

and regarding your code the reason it is not handle by switchMap is you return throwError which is not a promise ( you mark function with async)

change throwError(...) to throwError().toPromise() will work properly. but again don't rely on fetch to reject properly

You can return a Promise inside switchMap directly.

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

Don't use async as in switchMap(async (response: Response) => { })!

The problem is that async causes switchMap to return an Observable of whatever you return. So in your switchMap if response.ok == false you returned an Observable<Observable<never>> which then emitted an Observable<never> to your success callback.


Here are a few general ways to throw an error inside switchMap.

1. Return an Observable that errors.

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

2. Throw an error directly

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

3. Return a Promise that errors

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

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744212705a4563410.html

相关推荐

  • javascript - How to use Rxjs switchMap to throwError - Stack Overflow

    I have create a wrapper for fetch function. Based on the code below, test_3 passed but how e test_1 and

    8天前
    10

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信