自从我开始使用angular2以来,我已经将服务设置为返回T的Observable。在服务中,我将使用map()调用,使用这些服务的组件将只使用subscribe()等待响应。对于这些简单的场景,我并不需要深入研究rxjs,所以一切都很好。
我现在想实现以下目标:我正在使用Oauth2身份验证和刷新令牌。我想构建一个所有其他服务都将使用的api服务,当返回401错误时,它将透明地处理刷新令牌。因此,在401的情况下,我首先从OAuth2端点获取一个新令牌,然后使用新令牌重试我的请求。下面是工作良好的代码,带有承诺:
request(url: string, request: RequestOptionsArgs): Promise<Response> {
var me = this;
request.headers = request.headers || new Headers();
var isSecureCall: boolean = true; //url.toLowerCase().startsWith('https://');
if (isSecureCall === true) {
me.authService.setAuthorizationHeader(request.headers);
}
request.headers.append('Content-Type', 'application/json');
request.headers.append('Accept', 'application/json');
return this.http.request(url, request).toPromise()
.catch(initialError => {
if (initialError && initialError.status === 401 && isSecureCall === true) {
// token might be expired, try to refresh token.
return me.authService.refreshAuthentication().then((authenticationResult:AuthenticationResult) => {
if (authenticationResult.IsAuthenticated == true) {
// retry with new token
me.authService.setAuthorizationHeader(request.headers);
return this.http.request(url, request).toPromise();
}
return <any>Promise.reject(initialError);
});
}
else {
return <any>Promise.reject(initialError);
}
});
}
在上面的代码中,authService。refreshAuthentication()将获取新令牌并将其存储在localStorage中。authService。setAuthorizationHeader将把“Authorize”标头设置为先前更新的令牌。如果您查看catch方法,您会看到它返回一个promise(用于刷新令牌),该promise最终将返回另一个procese(用于请求的实际第二次尝试)。
我试图做到这一点,而不诉诸承诺:
request(url: string, request: RequestOptionsArgs): Observable<Response> {
var me = this;
request.headers = request.headers || new Headers();
var isSecureCall: boolean = true; //url.toLowerCase().startsWith('https://');
if (isSecureCall === true) {
me.authService.setAuthorizationHeader(request.headers);
}
request.headers.append('Content-Type', 'application/json');
request.headers.append('Accept', 'application/json');
return this.http.request(url, request)
.catch(initialError => {
if (initialError && initialError.status === 401 && isSecureCall === true) {
// token might be expired, try to refresh token
return me.authService.refreshAuthenticationObservable().map((authenticationResult:AuthenticationResult) => {
if (authenticationResult.IsAuthenticated == true) {
// retry with new token
me.authService.setAuthorizationHeader(request.headers);
return this.http.request(url, request);
}
return Observable.throw(initialError);
});
}
else {
return Observable.throw(initialError);
}
});
}
上面的代码没有达到我预期的效果:在200响应的情况下,它正确地返回了响应。然而,如果它捕捉到401,它将成功地检索到新令牌,但订阅最终将检索到可观察的而不是响应。我猜这是应该进行重试的未执行Observable。
我意识到,将promise的工作方式翻译到rxjs库上可能不是最好的方法,但我还没能理解“一切都是流”这一点。我尝试了一些其他的解决方案,包括平面图、retryWhen等……但效果并不理想,因此我们非常感谢您的帮助。