如何使用 Rxjs switchMap 抛出错误
How to use Rxjs switchMap to throwError
我已经为 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。
fetch 不会为您抛出错误
https://developer.mozilla.org/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 completing.
更新:
看起来您的 api 调用是 returning 401 并且将在 fetch 承诺中被拒绝,但您仍然不能依赖 fetch 来正确拒绝。请看下面的帖子
https://github.com/github/fetch/issues/201
关于你的代码,它不被 switchMap 处理的原因是你 return throwError 这不是一个承诺(你用异步标记函数)
将 throwError(...)
更改为 throwError().toPromise()
将正常工作。但同样不要依赖 fetch 来正确拒绝
您可以 return 直接在 switchMap
中使用 Promise。
switchMap(response => response.ok
? getBody(response)
: getBody(response).then(body => {
throw { status: response.status, statusText: response.statusText, body }
}))
)
不要像 switchMap(async (response: Response) => { })
那样使用 async
!
问题是async
导致switchMap
到return任何你return的Observable。因此,在您的 switchMap
if response.ok == false
中,您 return 编辑了一个 Observable<Observable<never>>
,然后它向您的成功回调发出了一个 Observable<never>
。
以下是在 switchMap
.
中抛出错误的几种通用方法
1. Return 一个出错的 Observable。
switchMap(response => response.ok
? of(successObject)
: throwError(errorObject)
)
2。直接抛出错误
switchMap(response => {
if (response.ok) {
return of(successObject)
} else {
throw errorObject
}
})
3。 Return 错误的 Promise
switchMap(response => response.ok
? Promise.resolve(successObject)
: Promise.reject(errorObject)
)
我已经为 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。
fetch 不会为您抛出错误
https://developer.mozilla.org/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 completing.
更新: 看起来您的 api 调用是 returning 401 并且将在 fetch 承诺中被拒绝,但您仍然不能依赖 fetch 来正确拒绝。请看下面的帖子
https://github.com/github/fetch/issues/201
关于你的代码,它不被 switchMap 处理的原因是你 return throwError 这不是一个承诺(你用异步标记函数)
将 throwError(...)
更改为 throwError().toPromise()
将正常工作。但同样不要依赖 fetch 来正确拒绝
您可以 return 直接在 switchMap
中使用 Promise。
switchMap(response => response.ok
? getBody(response)
: getBody(response).then(body => {
throw { status: response.status, statusText: response.statusText, body }
}))
)
不要像 switchMap(async (response: Response) => { })
那样使用 async
!
问题是async
导致switchMap
到return任何你return的Observable。因此,在您的 switchMap
if response.ok == false
中,您 return 编辑了一个 Observable<Observable<never>>
,然后它向您的成功回调发出了一个 Observable<never>
。
以下是在 switchMap
.
1. Return 一个出错的 Observable。
switchMap(response => response.ok
? of(successObject)
: throwError(errorObject)
)
2。直接抛出错误
switchMap(response => {
if (response.ok) {
return of(successObject)
} else {
throw errorObject
}
})
3。 Return 错误的 Promise
switchMap(response => response.ok
? Promise.resolve(successObject)
: Promise.reject(errorObject)
)