Я создал оболочку для функции извлечения. Исходя из приведенного ниже кода, 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
Пожалуйста, не предлагайте мне использовать ajax rxjs.
Всего 2 ответа
fetch не выдаст за вас ошибку
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
Обещание, возвращаемое функцией fetch (), не будет отклонять состояние ошибки HTTP, даже если ответом является HTTP 404 или 500. Вместо этого он будет разрешен в обычном режиме (при условии, что для состояния ok установлено значение false), и он будет отклоняться только при сбое сети или если что-то помешало выполнению запроса.
Обновление: похоже, ваш вызов API возвращает 401 и будет отклонен в обещании получения, но вы все еще не можете полагаться на получение для правильного отклонения. пожалуйста, смотрите ниже тему
https://github.com/github/fetch/issues/201
и в отношении вашего кода причина, по которой он не обрабатывается switchMap, заключается в том, что вы возвращаете throwError, который не является обещанием (вы помечаете функцию как async)
замените throwError(...)
на throwError().toPromise()
будет работать правильно. но опять же не полагайтесь на fetch для правильного отклонения
Удалите async
файл из вашей switchMap
и верните наблюдаемое с помощью of
.
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)
),
);
switchMap
заставляет switchMap
возвращать Observable того, что вы возвращаете. Таким образом, в вашем switchMap
если response.ok == false
вы вернули Observable<Observable<never>>
который затем отправил Observable<never>
в ваш успешный обратный вызов.