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 badges2 Answers
Reset to default 3fetch 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
评论列表(0条)