我正在使用Angular 2和RxJS从我的API层检索数据。我有一个基本服务,我已经编写,以处理HTTP请求。以下代码在我的服务中执行此操作:
protected apiGet(uri: string): Observable<HttpMappedResponse<T>> {
return this.mapAndHandle<T>(this.http.get(uri));
}
private mapAndHandle<T>(observable: Observable<Response>): Observable<HttpMappedResponse<T>> {
const o = observable
.map(res => {
const data = res.json() || {};
const mappedResponse = new HttpMappedResponse<T>(res, data);
// Retrieve page information from HTTP headers
mappedResponse.pageInfo = new PageInfo(res.headers);
return mappedResponse;
})
.share();
o.subscribe(null, e => this.errorService.handleHttpResponse(e));
return o;
}
这很有效,并且在我拨打apiGet()
时会向我提供所需的所有数据。我现在要做的是以下内容:
我尝试过使用.catch(),. retryWhen(),。map()和.flatMapTo()但没有成功 - 我最接近的是:
enum HttpVerb {
Put,
Post,
Get,
Delete
}
private mapAndHandle<T>(uri: string, type: HttpVerb): Observable<HttpMappedResponse<T>> {
const restObservable = this.getRestObservable(uri, type);
const o = restObservable
.map(res => this.mapToHttpMappedResponse<T>(res))
.catch((error, sourceObservable) => {
const data = error.json() || {};
if (error.status === 401 && data.Message === 'Token expired') {
console.log('Retrying');
// Refresh the expired auth token
const refreshToken = this.authService.userData.RefreshToken;
console.log(refreshToken);
this.authService
.refresh(new RefreshRequestModel(refreshToken))
.subscribe(x => null);
// Retry original
return this
.getRestObservable(uri, type)
.map(x => this.mapToHttpMappedResponse(x));
}
throw error;
})
.share();
o.subscribe(null, e => {
this.errorService.handleHttpResponse(e);
});
return o;
}
private mapToHttpMappedResponse<T>(res: Response): HttpMappedResponse<T> {
console.log('Attempt ' + Date.now());
const data = res.json() || {};
const mappedResponse = new HttpMappedResponse<T>(res, data);
// Retrieve page information from HTTP headers
mappedResponse.pageInfo = new PageInfo(res.headers);
return mappedResponse;
}
但这并没有给我正确的结果。
我可以使用操作员来执行此操作吗? retryWhen()似乎是最合乎逻辑的,但我只是让自己陷入混乱的RxJs!
答案 0 :(得分:1)
您遇到的一个问题是您没有连接电话。您的刷新调用应该链接到您的重试调用,他们应该利用flatMap
或类似的东西将它保存在同一个可观察的流中。
请看my answer这个问题。
这就是你如何实现它的目的:
您需要从RxJS添加catch
运算符。这是一个错误,你可以相应地处理它。
为了使刷新逻辑通过拦截器,您需要返回调用,函数也应该返回Observable
。例如,修改上面的原始逻辑:
this.http.request(url, options)
.map((res: Response) => res.json())
.catch((error: any) => {
const err = error.json();
// Refresh JWT
if (err.status === 401) {
// refreshToken makes another HTTP call and returns an Observable.
return this.refreshToken(...);
}
return Observable.throw(err);
});
如果您希望能够重试原始请求,您可以执行的操作是传递原始请求数据,以便在成功刷新令牌后,您可以再次进行呼叫。例如,这就是refreshToken
函数的外观:
refreshToken(url: string, options: RequestOptionsArgs, body: any, tokenData: any): Observable<any>
return this.post(`${this.url}/token/refresh`, tokenData)
.flatMap((res: any) => {
// May want to use response data to set new tokens in your local storage or whatever here...
// This is where I retry the original request
return this.request(url, options, body);
});
}